mirror of
https://github.com/gravitl/netmaker.git
synced 2025-10-05 08:47:35 +08:00
Combined client + server code, Added HA ability, minor bug fixes
This commit is contained in:
@@ -2,157 +2,15 @@ package controller
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/dnslogic"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"github.com/gravitl/netmaker/serverctl"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
func GetPeersList(networkName string, excludeRelayed bool, relayedNodeAddr string) ([]models.Node, error) {
|
||||
var peers []models.Node
|
||||
var relayNode models.Node
|
||||
var err error
|
||||
if relayedNodeAddr == "" {
|
||||
peers, err = GetNodePeers(networkName, excludeRelayed)
|
||||
|
||||
} else {
|
||||
relayNode, err = GetNodeRelay(networkName, relayedNodeAddr)
|
||||
if relayNode.Address != "" {
|
||||
relayNode = setPeerInfo(relayNode)
|
||||
network, err := models.GetNetwork(networkName)
|
||||
if err == nil {
|
||||
relayNode.AllowedIPs = append(relayNode.AllowedIPs, network.AddressRange)
|
||||
} else {
|
||||
relayNode.AllowedIPs = append(relayNode.AllowedIPs, relayNode.RelayAddrs...)
|
||||
}
|
||||
nodepeers, err := GetNodePeers(networkName, false)
|
||||
if err == nil && relayNode.UDPHolePunch == "yes" {
|
||||
for _, nodepeer := range nodepeers {
|
||||
if nodepeer.Address == relayNode.Address {
|
||||
relayNode.Endpoint = nodepeer.Endpoint
|
||||
relayNode.ListenPort = nodepeer.ListenPort
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
peers = append(peers, relayNode)
|
||||
}
|
||||
}
|
||||
return peers, err
|
||||
}
|
||||
|
||||
func GetNodePeers(networkName string, excludeRelayed bool) ([]models.Node, error) {
|
||||
var peers []models.Node
|
||||
collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
|
||||
if err != nil {
|
||||
if database.IsEmptyRecord(err) {
|
||||
return peers, nil
|
||||
}
|
||||
functions.PrintUserLog("", err.Error(), 2)
|
||||
return nil, err
|
||||
}
|
||||
udppeers, errN := database.GetPeers(networkName)
|
||||
if errN != nil {
|
||||
functions.PrintUserLog("", errN.Error(), 2)
|
||||
}
|
||||
for _, value := range collection {
|
||||
var node models.Node
|
||||
var peer models.Node
|
||||
err := json.Unmarshal([]byte(value), &node)
|
||||
if err != nil {
|
||||
functions.PrintUserLog("", err.Error(), 2)
|
||||
continue
|
||||
}
|
||||
if node.IsEgressGateway == "yes" { // handle egress stuff
|
||||
peer.EgressGatewayRanges = node.EgressGatewayRanges
|
||||
peer.IsEgressGateway = node.IsEgressGateway
|
||||
}
|
||||
allow := node.IsRelayed != "yes" || !excludeRelayed
|
||||
|
||||
if node.Network == networkName && node.IsPending != "yes" && allow {
|
||||
peer = setPeerInfo(node)
|
||||
if node.UDPHolePunch == "yes" && errN == nil && functions.CheckEndpoint(udppeers[node.PublicKey]) {
|
||||
endpointstring := udppeers[node.PublicKey]
|
||||
endpointarr := strings.Split(endpointstring, ":")
|
||||
if len(endpointarr) == 2 {
|
||||
port, err := strconv.Atoi(endpointarr[1])
|
||||
if err == nil {
|
||||
peer.Endpoint = endpointarr[0]
|
||||
peer.ListenPort = int32(port)
|
||||
}
|
||||
}
|
||||
}
|
||||
if node.IsRelay == "yes" {
|
||||
network, err := models.GetNetwork(networkName)
|
||||
if err == nil {
|
||||
peer.AllowedIPs = append(peer.AllowedIPs, network.AddressRange)
|
||||
} else {
|
||||
peer.AllowedIPs = append(peer.AllowedIPs, node.RelayAddrs...)
|
||||
}
|
||||
}
|
||||
peers = append(peers, peer)
|
||||
}
|
||||
}
|
||||
|
||||
return peers, err
|
||||
}
|
||||
|
||||
func setPeerInfo(node models.Node) models.Node {
|
||||
var peer models.Node
|
||||
peer.RelayAddrs = node.RelayAddrs
|
||||
peer.IsRelay = node.IsRelay
|
||||
peer.IsRelayed = node.IsRelayed
|
||||
peer.PublicKey = node.PublicKey
|
||||
peer.Endpoint = node.Endpoint
|
||||
peer.LocalAddress = node.LocalAddress
|
||||
peer.ListenPort = node.ListenPort
|
||||
peer.AllowedIPs = node.AllowedIPs
|
||||
peer.UDPHolePunch = node.UDPHolePunch
|
||||
peer.Address = node.Address
|
||||
peer.Address6 = node.Address6
|
||||
peer.EgressGatewayRanges = node.EgressGatewayRanges
|
||||
peer.IsEgressGateway = node.IsEgressGateway
|
||||
peer.IngressGatewayRange = node.IngressGatewayRange
|
||||
peer.IsIngressGateway = node.IsIngressGateway
|
||||
peer.IsPending = node.IsPending
|
||||
return peer
|
||||
}
|
||||
|
||||
func GetExtPeersList(macaddress string, networkName string) ([]models.ExtPeersResponse, error) {
|
||||
|
||||
var peers []models.ExtPeersResponse
|
||||
records, err := database.FetchRecords(database.EXT_CLIENT_TABLE_NAME)
|
||||
|
||||
if err != nil {
|
||||
return peers, err
|
||||
}
|
||||
|
||||
for _, value := range records {
|
||||
var peer models.ExtPeersResponse
|
||||
var extClient models.ExtClient
|
||||
err = json.Unmarshal([]byte(value), &peer)
|
||||
if err != nil {
|
||||
functions.PrintUserLog(models.NODE_SERVER_NAME, "failed to unmarshal peer", 2)
|
||||
continue
|
||||
}
|
||||
err = json.Unmarshal([]byte(value), &extClient)
|
||||
if err != nil {
|
||||
functions.PrintUserLog(models.NODE_SERVER_NAME, "failed to unmarshal ext client", 2)
|
||||
continue
|
||||
}
|
||||
if extClient.Network == networkName && extClient.IngressGatewayID == macaddress {
|
||||
peers = append(peers, peer)
|
||||
}
|
||||
}
|
||||
return peers, err
|
||||
}
|
||||
|
||||
/**
|
||||
* If being deleted by server, create a record in the DELETED_NODES_TABLE for the client to find
|
||||
* If being deleted by the client, delete completely
|
||||
@@ -183,7 +41,7 @@ func DeleteNode(key string, exterminate bool) error {
|
||||
return err
|
||||
}
|
||||
if servercfg.IsDNSMode() {
|
||||
err = SetDNS()
|
||||
err = dnslogic.SetDNS()
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -235,93 +93,3 @@ func GetIntClient(clientid string) (models.IntClient, error) {
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func CreateNode(node models.Node, networkName string) (models.Node, error) {
|
||||
|
||||
//encrypt that password so we never see it
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(node.Password), 5)
|
||||
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
//set password to encrypted password
|
||||
node.Password = string(hash)
|
||||
|
||||
node.Network = networkName
|
||||
if node.Name == models.NODE_SERVER_NAME {
|
||||
node.IsServer = "yes"
|
||||
}
|
||||
if servercfg.IsDNSMode() && node.DNSOn == ""{
|
||||
node.DNSOn = "yes"
|
||||
}
|
||||
node.SetDefaults()
|
||||
node.Address, err = functions.UniqueAddress(networkName)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
node.Address6, err = functions.UniqueAddress6(networkName)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
//Create a JWT for the node
|
||||
tokenString, _ := functions.CreateJWT(node.MacAddress, networkName)
|
||||
if tokenString == "" {
|
||||
//returnErrorResponse(w, r, errorResponse)
|
||||
return node, err
|
||||
}
|
||||
err = node.Validate(false)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
key, err := functions.GetRecordKey(node.MacAddress, node.Network)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
nodebytes, err := json.Marshal(&node)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
err = database.Insert(key, string(nodebytes), database.NODES_TABLE_NAME)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
if node.IsPending != "yes" {
|
||||
functions.DecrimentKey(node.Network, node.AccessKey)
|
||||
}
|
||||
SetNetworkNodesLastModified(node.Network)
|
||||
if servercfg.IsDNSMode() {
|
||||
err = SetDNS()
|
||||
}
|
||||
return node, err
|
||||
}
|
||||
|
||||
func SetNetworkServerPeers(networkName string) {
|
||||
if currentPeersList, err := serverctl.GetPeers(networkName); err == nil {
|
||||
if database.SetPeers(currentPeersList, networkName) {
|
||||
functions.PrintUserLog(models.NODE_SERVER_NAME, "set new peers on network "+networkName, 1)
|
||||
}
|
||||
} else {
|
||||
functions.PrintUserLog(models.NODE_SERVER_NAME, "could not set peers on network "+networkName, 1)
|
||||
functions.PrintUserLog(models.NODE_SERVER_NAME, err.Error(), 1)
|
||||
}
|
||||
}
|
||||
|
||||
func SetNetworkNodesLastModified(networkName string) error {
|
||||
|
||||
timestamp := time.Now().Unix()
|
||||
|
||||
network, err := functions.GetParentNetwork(networkName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
network.NodesLastModified = timestamp
|
||||
data, err := json.Marshal(&network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = database.Insert(networkName, string(data), database.NETWORKS_TABLE_NAME)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -13,20 +14,20 @@ func TestGetPeerList(t *testing.T) {
|
||||
deleteAllNetworks()
|
||||
createNet()
|
||||
t.Run("NoNodes", func(t *testing.T) {
|
||||
peers, err := GetPeersList("skynet", false, "")
|
||||
peers, err := logic.GetPeersList("skynet", false, "")
|
||||
assert.Nil(t, err)
|
||||
assert.Nil(t, peers)
|
||||
})
|
||||
node := createTestNode()
|
||||
t.Run("One Node", func(t *testing.T) {
|
||||
peers, err := GetPeersList("skynet", false, "")
|
||||
peers, err := logic.GetPeersList("skynet", false, "")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, node.Address, peers[0].Address)
|
||||
})
|
||||
t.Run("Multiple Nodes", func(t *testing.T) {
|
||||
createnode := models.Node{PublicKey: "RM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Endpoint: "10.0.0.2", MacAddress: "02:02:03:04:05:06", Password: "password", Network: "skynet"}
|
||||
CreateNode(createnode, "skynet")
|
||||
peers, err := GetPeersList("skynet", false, "")
|
||||
logic.CreateNode(createnode, "skynet")
|
||||
peers, err := logic.GetPeersList("skynet", false, "")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, len(peers), 2)
|
||||
foundNodeEndpoint := false
|
||||
@@ -97,7 +98,7 @@ func TestCreateNode(t *testing.T) {
|
||||
createnode := models.Node{PublicKey: "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Endpoint: "10.0.0.1", MacAddress: "01:02:03:04:05:06", Password: "password", Network: "skynet"}
|
||||
//err := ValidateNodeCreate("skynet", createnode)
|
||||
//assert.Nil(t, err)
|
||||
node, err := CreateNode(createnode, "skynet")
|
||||
node, err := logic.CreateNode(createnode, "skynet")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "10.0.0.1", node.Endpoint)
|
||||
assert.Equal(t, "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", node.PublicKey)
|
||||
@@ -113,17 +114,17 @@ func TestSetNetworkNodesLastModified(t *testing.T) {
|
||||
deleteAllNetworks()
|
||||
createNet()
|
||||
t.Run("InvalidNetwork", func(t *testing.T) {
|
||||
err := SetNetworkNodesLastModified("badnet")
|
||||
err := logic.SetNetworkNodesLastModified("badnet")
|
||||
assert.EqualError(t, err, "no result found")
|
||||
})
|
||||
t.Run("NetworkExists", func(t *testing.T) {
|
||||
err := SetNetworkNodesLastModified("skynet")
|
||||
err := logic.SetNetworkNodesLastModified("skynet")
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func createTestNode() models.Node {
|
||||
createnode := models.Node{PublicKey: "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Endpoint: "10.0.0.1", MacAddress: "01:02:03:04:05:06", Password: "password", Network: "skynet"}
|
||||
node, _ := CreateNode(createnode, "skynet")
|
||||
node, _ := logic.CreateNode(createnode, "skynet")
|
||||
return node
|
||||
}
|
||||
|
@@ -3,13 +3,13 @@ package controller
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/dnslogic"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"github.com/txn2/txeh"
|
||||
)
|
||||
|
||||
func dnsHandlers(r *mux.Router) {
|
||||
@@ -63,7 +63,7 @@ func GetAllDNS() ([]models.DNSEntry, error) {
|
||||
return []models.DNSEntry{}, err
|
||||
}
|
||||
for _, net := range networks {
|
||||
netdns, err := GetDNS(net.NetID)
|
||||
netdns, err := dnslogic.GetDNS(net.NetID)
|
||||
if err != nil {
|
||||
return []models.DNSEntry{}, nil
|
||||
}
|
||||
@@ -103,7 +103,7 @@ func getCustomDNS(w http.ResponseWriter, r *http.Request) {
|
||||
var dns []models.DNSEntry
|
||||
var params = mux.Vars(r)
|
||||
|
||||
dns, err := GetCustomDNS(params["network"])
|
||||
dns, err := dnslogic.GetCustomDNS(params["network"])
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
@@ -114,65 +114,11 @@ func getCustomDNS(w http.ResponseWriter, r *http.Request) {
|
||||
json.NewEncoder(w).Encode(dns)
|
||||
}
|
||||
|
||||
func GetCustomDNS(network string) ([]models.DNSEntry, error) {
|
||||
|
||||
var dns []models.DNSEntry
|
||||
|
||||
collection, err := database.FetchRecords(database.DNS_TABLE_NAME)
|
||||
if err != nil {
|
||||
return dns, err
|
||||
}
|
||||
for _, value := range collection { // filter for entries based on network
|
||||
var entry models.DNSEntry
|
||||
if err := json.Unmarshal([]byte(value), &entry); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if entry.Network == network {
|
||||
dns = append(dns, entry)
|
||||
}
|
||||
}
|
||||
|
||||
return dns, err
|
||||
}
|
||||
|
||||
func SetDNS() error {
|
||||
hostfile := txeh.Hosts{}
|
||||
var corefilestring string
|
||||
networks, err := models.GetNetworks()
|
||||
if err != nil && !database.IsEmptyRecord(err){
|
||||
return err
|
||||
}
|
||||
|
||||
for _, net := range networks {
|
||||
corefilestring = corefilestring + net.NetID + " "
|
||||
dns, err := GetDNS(net.NetID)
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return err
|
||||
}
|
||||
for _, entry := range dns {
|
||||
hostfile.AddHost(entry.Address, entry.Name+"."+entry.Network)
|
||||
}
|
||||
}
|
||||
if corefilestring == "" {
|
||||
corefilestring = "example.com"
|
||||
}
|
||||
|
||||
err = hostfile.SaveAs("./config/dnsconfig/netmaker.hosts")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if servercfg.IsSplitDNS() {
|
||||
err = functions.SetCorefile(corefilestring)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func GetDNSEntryNum(domain string, network string) (int, error) {
|
||||
|
||||
num := 0
|
||||
|
||||
entries, err := GetDNS(network)
|
||||
entries, err := dnslogic.GetDNS(network)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -195,7 +141,7 @@ func getDNS(w http.ResponseWriter, r *http.Request) {
|
||||
var dns []models.DNSEntry
|
||||
var params = mux.Vars(r)
|
||||
|
||||
dns, err := GetDNS(params["network"])
|
||||
dns, err := dnslogic.GetDNS(params["network"])
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
@@ -204,22 +150,6 @@ func getDNS(w http.ResponseWriter, r *http.Request) {
|
||||
json.NewEncoder(w).Encode(dns)
|
||||
}
|
||||
|
||||
func GetDNS(network string) ([]models.DNSEntry, error) {
|
||||
|
||||
var dns []models.DNSEntry
|
||||
dns, err := GetNodeDNS(network)
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return dns, err
|
||||
}
|
||||
customdns, err := GetCustomDNS(network)
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return dns, err
|
||||
}
|
||||
|
||||
dns = append(dns, customdns...)
|
||||
return dns, nil
|
||||
}
|
||||
|
||||
func createDNS(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
@@ -241,7 +171,7 @@ func createDNS(w http.ResponseWriter, r *http.Request) {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
err = SetDNS()
|
||||
err = dnslogic.SetDNS()
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
@@ -296,7 +226,7 @@ func updateDNS(w http.ResponseWriter, r *http.Request) {
|
||||
returnErrorResponse(w, r, formatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
err = SetDNS()
|
||||
err = dnslogic.SetDNS()
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
@@ -319,7 +249,7 @@ func deleteDNS(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
entrytext := params["domain"] + "." + params["network"]
|
||||
functions.PrintUserLog(models.NODE_SERVER_NAME, "deleted dns entry: "+entrytext, 1)
|
||||
err = SetDNS()
|
||||
err = dnslogic.SetDNS()
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
@@ -394,13 +324,13 @@ func pushDNS(w http.ResponseWriter, r *http.Request) {
|
||||
// Set header
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
err := SetDNS()
|
||||
err := dnslogic.SetDNS()
|
||||
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
functions.PrintUserLog(r.Header.Get("user"),"pushed DNS updates to nameserver",1)
|
||||
functions.PrintUserLog(r.Header.Get("user"), "pushed DNS updates to nameserver", 1)
|
||||
json.NewEncoder(w).Encode("DNS Pushed to CoreDNS")
|
||||
}
|
||||
|
||||
@@ -421,7 +351,7 @@ func ValidateDNSCreate(entry models.DNSEntry) error {
|
||||
err := v.Struct(entry)
|
||||
if err != nil {
|
||||
for _, e := range err.(validator.ValidationErrors) {
|
||||
functions.PrintUserLog("", e.Error(),1)
|
||||
functions.PrintUserLog("", e.Error(), 1)
|
||||
}
|
||||
}
|
||||
return err
|
||||
@@ -442,7 +372,7 @@ func ValidateDNSUpdate(change models.DNSEntry, entry models.DNSEntry) error {
|
||||
_ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
|
||||
_, err := functions.GetParentNetwork(change.Network)
|
||||
if err != nil {
|
||||
functions.PrintUserLog("",err.Error(),0)
|
||||
functions.PrintUserLog("", err.Error(), 0)
|
||||
}
|
||||
return err == nil
|
||||
})
|
||||
@@ -465,7 +395,7 @@ func ValidateDNSUpdate(change models.DNSEntry, entry models.DNSEntry) error {
|
||||
|
||||
if err != nil {
|
||||
for _, e := range err.(validator.ValidationErrors) {
|
||||
functions.PrintUserLog("", e.Error(),1)
|
||||
functions.PrintUserLog("", e.Error(), 1)
|
||||
}
|
||||
}
|
||||
return err
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/dnslogic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -23,7 +24,7 @@ func TestGetCustomDNS(t *testing.T) {
|
||||
deleteAllNetworks()
|
||||
createNet()
|
||||
createTestNode()
|
||||
dns, err := GetCustomDNS("skynet")
|
||||
dns, err := dnslogic.GetCustomDNS("skynet")
|
||||
assert.Nil(t, err)
|
||||
t.Log(dns)
|
||||
}
|
||||
@@ -39,7 +40,7 @@ func TestGetDNSEntryNum(t *testing.T) {
|
||||
func TestGetDNS(t *testing.T) {
|
||||
database.InitializeDatabase()
|
||||
deleteAllNetworks()
|
||||
dns, err := GetDNS("skynet")
|
||||
dns, err := dnslogic.GetDNS("skynet")
|
||||
assert.Nil(t, err)
|
||||
t.Log(dns)
|
||||
}
|
||||
|
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/skip2/go-qrcode"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
@@ -273,7 +274,7 @@ func CreateExtClient(extclient models.ExtClient) error {
|
||||
if err = database.Insert(key, string(data), database.EXT_CLIENT_TABLE_NAME); err != nil {
|
||||
return err
|
||||
}
|
||||
err = SetNetworkNodesLastModified(extclient.Network)
|
||||
err = logic.SetNetworkNodesLastModified(extclient.Network)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"github.com/gravitl/netmaker/serverctl"
|
||||
@@ -337,8 +338,21 @@ func deleteNetwork(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func DeleteNetwork(network string) error {
|
||||
nodeCount, err := functions.GetNetworkNodeCount(network)
|
||||
nodeCount, err := functions.GetNetworkNonServerNodeCount(network)
|
||||
if nodeCount == 0 || database.IsEmptyRecord(err) {
|
||||
// delete server nodes first then db records
|
||||
servers, err := logic.GetSortedNetworkServerNodes(network)
|
||||
if err == nil {
|
||||
for _, s := range servers {
|
||||
if err = logic.DeleteNode(s.ID, true); err != nil {
|
||||
functions.PrintUserLog("[netmaker]", "could not removed server "+s.Name+" before deleting network "+network, 2)
|
||||
} else {
|
||||
functions.PrintUserLog("[netmaker]", "removed server "+s.Name+" before deleting network "+network, 2)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
functions.PrintUserLog("[netmaker]", "could not remove servers before deleting network "+network, 1)
|
||||
}
|
||||
return database.DeleteRecord(database.NETWORKS_TABLE_NAME, network)
|
||||
}
|
||||
return errors.New("node check failed. All nodes must be deleted before deleting network")
|
||||
@@ -465,15 +479,15 @@ func CreateAccessKey(accesskey models.AccessKey, network models.Network) (models
|
||||
var accessToken models.AccessToken
|
||||
s := servercfg.GetServerConfig()
|
||||
servervals := models.ServerConfig{
|
||||
CoreDNSAddr: s.CoreDNSAddr,
|
||||
APIConnString: s.APIConnString,
|
||||
APIHost: s.APIHost,
|
||||
APIPort: s.APIPort,
|
||||
GRPCConnString: s.GRPCConnString,
|
||||
GRPCHost: s.GRPCHost,
|
||||
GRPCPort: s.GRPCPort,
|
||||
GRPCSSL: s.GRPCSSL,
|
||||
CheckinInterval: s.CheckinInterval,
|
||||
CoreDNSAddr: s.CoreDNSAddr,
|
||||
APIConnString: s.APIConnString,
|
||||
APIHost: s.APIHost,
|
||||
APIPort: s.APIPort,
|
||||
GRPCConnString: s.GRPCConnString,
|
||||
GRPCHost: s.GRPCHost,
|
||||
GRPCPort: s.GRPCPort,
|
||||
GRPCSSL: s.GRPCSSL,
|
||||
CheckinInterval: s.CheckinInterval,
|
||||
}
|
||||
accessToken.ServerConfig = servervals
|
||||
accessToken.ClientConfig.Network = netID
|
||||
|
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
nodepb "github.com/gravitl/netmaker/grpc"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
)
|
||||
|
||||
@@ -67,7 +68,7 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.Object)
|
||||
}
|
||||
}
|
||||
|
||||
node, err = CreateNode(node, node.Network)
|
||||
node, err = logic.CreateNode(node, node.Network)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -77,7 +78,7 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.Object)
|
||||
Data: string(nodeData),
|
||||
Type: nodepb.NODE_TYPE,
|
||||
}
|
||||
err = SetNetworkNodesLastModified(node.Network)
|
||||
err = logic.SetNetworkNodesLastModified(node.Network)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -134,15 +135,15 @@ func (s *NodeServiceServer) GetPeers(ctx context.Context, req *nodepb.Object) (*
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if node.IsServer == "yes" {
|
||||
SetNetworkServerPeers(macAndNetwork[1])
|
||||
if node.IsServer == "yes" && logic.IsLeader(&node){
|
||||
logic.SetNetworkServerPeers(&node)
|
||||
}
|
||||
excludeIsRelayed := node.IsRelay != "yes"
|
||||
var relayedNode string
|
||||
if node.IsRelayed == "yes" {
|
||||
relayedNode = node.Address
|
||||
}
|
||||
peers, err := GetPeersList(macAndNetwork[1], excludeIsRelayed, relayedNode)
|
||||
peers, err := logic.GetPeersList(macAndNetwork[1], excludeIsRelayed, relayedNode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -172,11 +173,10 @@ func (s *NodeServiceServer) GetExtPeers(ctx context.Context, req *nodepb.Object)
|
||||
if len(macAndNetwork) != 2 {
|
||||
return nil, errors.New("did not receive valid node id when fetching ext peers")
|
||||
}
|
||||
peers, err := GetExtPeersList(macAndNetwork[0], macAndNetwork[1])
|
||||
peers, err := logic.GetExtPeersList(macAndNetwork[0], macAndNetwork[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// cursor.Next() returns a boolean, if false there are no more items and loop will break
|
||||
var extPeers []models.Node
|
||||
for i := 0; i < len(peers); i++ {
|
||||
extPeers = append(extPeers, models.Node{
|
||||
|
@@ -6,10 +6,11 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/dnslogic"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
@@ -267,7 +268,7 @@ func getNetworkNodes(w http.ResponseWriter, r *http.Request) {
|
||||
var nodes []models.Node
|
||||
var params = mux.Vars(r)
|
||||
networkName := params["network"]
|
||||
nodes, err := GetNetworkNodes(networkName)
|
||||
nodes, err := logic.GetNetworkNodes(networkName)
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
@@ -279,29 +280,6 @@ func getNetworkNodes(w http.ResponseWriter, r *http.Request) {
|
||||
json.NewEncoder(w).Encode(nodes)
|
||||
}
|
||||
|
||||
func GetNetworkNodes(network string) ([]models.Node, error) {
|
||||
var nodes []models.Node
|
||||
collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
|
||||
if err != nil {
|
||||
if database.IsEmptyRecord(err) {
|
||||
return []models.Node{}, nil
|
||||
}
|
||||
return nodes, err
|
||||
}
|
||||
for _, value := range collection {
|
||||
|
||||
var node models.Node
|
||||
err := json.Unmarshal([]byte(value), &node)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if node.Network == network {
|
||||
nodes = append(nodes, node)
|
||||
}
|
||||
}
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
//A separate function to get all nodes, not just nodes for a particular network.
|
||||
//Not quite sure if this is necessary. Probably necessary based on front end but may want to review after iteration 1 if it's being used or not
|
||||
func getAllNodes(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -335,7 +313,7 @@ func getUsersNodes(user models.User) ([]models.Node, error) {
|
||||
var nodes []models.Node
|
||||
var err error
|
||||
for _, networkName := range user.Networks {
|
||||
tmpNodes, err := GetNetworkNodes(networkName)
|
||||
tmpNodes, err := logic.GetNetworkNodes(networkName)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
@@ -437,7 +415,7 @@ func createNode(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
node, err = CreateNode(node, networkName)
|
||||
node, err = logic.CreateNode(node, networkName)
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
@@ -682,7 +660,7 @@ func CreateIngressGateway(netid string, macaddress string) (models.Node, error)
|
||||
if err != nil {
|
||||
return models.Node{}, err
|
||||
}
|
||||
err = SetNetworkNodesLastModified(netid)
|
||||
err = logic.SetNetworkNodesLastModified(netid)
|
||||
return node, err
|
||||
}
|
||||
|
||||
@@ -733,7 +711,7 @@ func DeleteIngressGateway(networkName string, macaddress string) (models.Node, e
|
||||
if err != nil {
|
||||
return models.Node{}, err
|
||||
}
|
||||
err = SetNetworkNodesLastModified(networkName)
|
||||
err = logic.SetNetworkNodesLastModified(networkName)
|
||||
return node, err
|
||||
}
|
||||
|
||||
@@ -783,7 +761,7 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if servercfg.IsDNSMode() {
|
||||
err = SetDNS()
|
||||
err = dnslogic.SetDNS()
|
||||
}
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -81,19 +82,19 @@ func TestGetNetworkNodes(t *testing.T) {
|
||||
deleteAllNetworks()
|
||||
createNet()
|
||||
t.Run("BadNet", func(t *testing.T) {
|
||||
node, err := GetNetworkNodes("badnet")
|
||||
node, err := logic.GetNetworkNodes("badnet")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, []models.Node{}, node)
|
||||
//assert.Equal(t, "mongo: no documents in result", err.Error())
|
||||
})
|
||||
t.Run("NoNodes", func(t *testing.T) {
|
||||
node, err := GetNetworkNodes("skynet")
|
||||
node, err := logic.GetNetworkNodes("skynet")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, []models.Node{}, node)
|
||||
})
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
createTestNode()
|
||||
node, err := GetNetworkNodes("skynet")
|
||||
node, err := logic.GetNetworkNodes("skynet")
|
||||
assert.Nil(t, err)
|
||||
assert.NotEqual(t, []models.Node(nil), node)
|
||||
})
|
||||
|
@@ -72,6 +72,21 @@ func CreateRelay(relay models.RelayRequest) (models.Node, error) {
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func deleteRelay(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
var params = mux.Vars(r)
|
||||
nodeMac := params["macaddress"]
|
||||
netid := params["network"]
|
||||
node, err := DeleteRelay(netid, nodeMac)
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
functions.PrintUserLog(r.Header.Get("user"), "deleted egress gateway "+nodeMac+" on network "+netid, 1)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(node)
|
||||
}
|
||||
|
||||
func SetRelayedNodes(yesOrno string, networkName string, addrs []string) error {
|
||||
|
||||
collections, err := database.FetchRecords(database.NODES_TABLE_NAME)
|
||||
@@ -125,21 +140,6 @@ func UpdateRelay(network string, oldAddrs []string, newAddrs []string) {
|
||||
}
|
||||
}
|
||||
|
||||
func deleteRelay(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
var params = mux.Vars(r)
|
||||
nodeMac := params["macaddress"]
|
||||
netid := params["network"]
|
||||
node, err := DeleteRelay(netid, nodeMac)
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
functions.PrintUserLog(r.Header.Get("user"), "deleted egress gateway "+nodeMac+" on network "+netid, 1)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(node)
|
||||
}
|
||||
|
||||
func DeleteRelay(network, macaddress string) (models.Node, error) {
|
||||
|
||||
node, err := functions.GetNodeByMacAddress(network, macaddress)
|
||||
@@ -171,30 +171,3 @@ func DeleteRelay(network, macaddress string) (models.Node, error) {
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func GetNodeRelay(network string, relayedNodeAddr string) (models.Node, error) {
|
||||
collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
|
||||
var relay models.Node
|
||||
if err != nil {
|
||||
if database.IsEmptyRecord(err) {
|
||||
return relay, nil
|
||||
}
|
||||
functions.PrintUserLog("", err.Error(), 2)
|
||||
return relay, err
|
||||
}
|
||||
for _, value := range collection {
|
||||
err := json.Unmarshal([]byte(value), &relay)
|
||||
if err != nil {
|
||||
functions.PrintUserLog("", err.Error(), 2)
|
||||
continue
|
||||
}
|
||||
if relay.IsRelay == "yes" {
|
||||
for _, addr := range relay.RelayAddrs {
|
||||
if addr == relayedNodeAddr {
|
||||
return relay, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return relay, errors.New("could not find relay for node " + relayedNodeAddr)
|
||||
}
|
||||
|
@@ -89,17 +89,17 @@ func VerifyAuthRequest(authRequest models.UserAuthParams) (string, error) {
|
||||
//Search DB for node with Mac Address. Ignore pending nodes (they should not be able to authenticate with API untill approved).
|
||||
record, err := database.FetchRecord(database.USERS_TABLE_NAME, authRequest.UserName)
|
||||
if err != nil {
|
||||
return "", errors.New("user " + authRequest.UserName + " not found")
|
||||
return "", errors.New("incorrect credentials")
|
||||
}
|
||||
if err = json.Unmarshal([]byte(record), &result); err != nil {
|
||||
return "", errors.New("user " + authRequest.UserName + " not found")
|
||||
return "", errors.New("incorrect credentials")
|
||||
}
|
||||
|
||||
//compare password from request to stored password in database
|
||||
//might be able to have a common hash (certificates?) and compare those so that a password isn't passed in in plain text...
|
||||
//TODO: Consider a way of hashing the password client side before sending, or using certificates
|
||||
if err = bcrypt.CompareHashAndPassword([]byte(result.Password), []byte(authRequest.Password)); err != nil {
|
||||
return "", errors.New("wrong password")
|
||||
return "", errors.New("incorrect credentials")
|
||||
}
|
||||
|
||||
//Create a new JWT for the node
|
||||
|
@@ -219,7 +219,7 @@ func TestVerifyAuthRequest(t *testing.T) {
|
||||
authRequest.Password = "password"
|
||||
jwt, err := VerifyAuthRequest(authRequest)
|
||||
assert.Equal(t, "", jwt)
|
||||
assert.EqualError(t, err, "user admin not found")
|
||||
assert.EqualError(t, err, "incorrect credentials")
|
||||
})
|
||||
t.Run("Non-Admin", func(t *testing.T) {
|
||||
user := models.User{"nonadmin", "somepass", nil, false}
|
||||
@@ -235,7 +235,7 @@ func TestVerifyAuthRequest(t *testing.T) {
|
||||
authRequest := models.UserAuthParams{"admin", "badpass"}
|
||||
jwt, err := VerifyAuthRequest(authRequest)
|
||||
assert.Equal(t, "", jwt)
|
||||
assert.EqualError(t, err, "wrong password")
|
||||
assert.EqualError(t, err, "incorrect credentials")
|
||||
})
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
authRequest := models.UserAuthParams{"admin", "password"}
|
||||
|
104
dnslogic/dns.go
Normal file
104
dnslogic/dns.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package dnslogic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"github.com/txn2/txeh"
|
||||
)
|
||||
|
||||
func SetDNS() error {
|
||||
hostfile := txeh.Hosts{}
|
||||
var corefilestring string
|
||||
networks, err := models.GetNetworks()
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, net := range networks {
|
||||
corefilestring = corefilestring + net.NetID + " "
|
||||
dns, err := GetDNS(net.NetID)
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return err
|
||||
}
|
||||
for _, entry := range dns {
|
||||
hostfile.AddHost(entry.Address, entry.Name+"."+entry.Network)
|
||||
}
|
||||
}
|
||||
if corefilestring == "" {
|
||||
corefilestring = "example.com"
|
||||
}
|
||||
|
||||
err = hostfile.SaveAs("./config/dnsconfig/netmaker.hosts")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if servercfg.IsSplitDNS() {
|
||||
err = functions.SetCorefile(corefilestring)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func GetDNS(network string) ([]models.DNSEntry, error) {
|
||||
|
||||
var dns []models.DNSEntry
|
||||
dns, err := GetNodeDNS(network)
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return dns, err
|
||||
}
|
||||
customdns, err := GetCustomDNS(network)
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return dns, err
|
||||
}
|
||||
|
||||
dns = append(dns, customdns...)
|
||||
return dns, nil
|
||||
}
|
||||
|
||||
func GetNodeDNS(network string) ([]models.DNSEntry, error) {
|
||||
|
||||
var dns []models.DNSEntry
|
||||
|
||||
collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
|
||||
if err != nil {
|
||||
return dns, err
|
||||
}
|
||||
|
||||
for _, value := range collection {
|
||||
var entry models.DNSEntry
|
||||
var node models.Node
|
||||
if err = json.Unmarshal([]byte(value), &node); err != nil {
|
||||
continue
|
||||
}
|
||||
if err = json.Unmarshal([]byte(value), &entry); node.Network == network && err == nil {
|
||||
dns = append(dns, entry)
|
||||
}
|
||||
}
|
||||
|
||||
return dns, nil
|
||||
}
|
||||
|
||||
func GetCustomDNS(network string) ([]models.DNSEntry, error) {
|
||||
|
||||
var dns []models.DNSEntry
|
||||
|
||||
collection, err := database.FetchRecords(database.DNS_TABLE_NAME)
|
||||
if err != nil {
|
||||
return dns, err
|
||||
}
|
||||
for _, value := range collection { // filter for entries based on network
|
||||
var entry models.DNSEntry
|
||||
if err := json.Unmarshal([]byte(value), &entry); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if entry.Network == network {
|
||||
dns = append(dns, entry)
|
||||
}
|
||||
}
|
||||
|
||||
return dns, err
|
||||
}
|
@@ -9,24 +9,16 @@ ENV GO111MODULE=auto
|
||||
|
||||
RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=1 /usr/local/go/bin/go build -ldflags="-w -s" -o netmaker main.go
|
||||
|
||||
WORKDIR /app/netclient
|
||||
|
||||
RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 /usr/local/go/bin/go build -ldflags="-w -s" -o netclient main.go
|
||||
#second stage
|
||||
|
||||
FROM alpine:3.13.6
|
||||
# add a c lib
|
||||
RUN apk add gcompat iptables
|
||||
# set the working directory
|
||||
WORKDIR /root/
|
||||
|
||||
RUN mkdir /etc/netclient
|
||||
RUN mkdir -p /etc/netclient/config
|
||||
|
||||
COPY --from=builder /app/netmaker .
|
||||
COPY --from=builder /app/config config
|
||||
COPY --from=builder /app/netclient/netclient /etc/netclient/netclient
|
||||
|
||||
RUN chmod 0755 /etc/netclient/netclient
|
||||
|
||||
EXPOSE 8081
|
||||
EXPOSE 50051
|
||||
|
@@ -20,11 +20,6 @@ import (
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
)
|
||||
|
||||
func CheckEndpoint(endpoint string) bool {
|
||||
endpointarr := strings.Split(endpoint, ":")
|
||||
return len(endpointarr) == 2
|
||||
}
|
||||
|
||||
func PrintUserLog(username string, message string, loglevel int) {
|
||||
log.SetFlags(log.Flags() &^ (log.Llongfile | log.Lshortfile))
|
||||
if int32(loglevel) <= servercfg.GetVerbose() && servercfg.GetVerbose() != 0 {
|
||||
@@ -103,9 +98,9 @@ func CreateServerToken(netID string) (string, error) {
|
||||
} else {
|
||||
log.Println("server on linux")
|
||||
servervals = models.ServerConfig{
|
||||
APIConnString: "127.0.0.1:" + servercfg.GetAPIPort(),
|
||||
GRPCConnString: "127.0.0.1:" + servercfg.GetGRPCPort(),
|
||||
GRPCSSL: "off",
|
||||
APIConnString: "127.0.0.1:" + servercfg.GetAPIPort(),
|
||||
GRPCConnString: "127.0.0.1:" + servercfg.GetGRPCPort(),
|
||||
GRPCSSL: "off",
|
||||
CheckinInterval: servercfg.GetCheckinInterval(),
|
||||
}
|
||||
}
|
||||
@@ -380,7 +375,7 @@ func IsMacAddressUnique(macaddress string, networkName string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func GetNetworkNodeCount(networkName string) (int, error) {
|
||||
func GetNetworkNonServerNodeCount(networkName string) (int, error) {
|
||||
|
||||
collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
|
||||
count := 0
|
||||
@@ -392,7 +387,7 @@ func GetNetworkNodeCount(networkName string) (int, error) {
|
||||
if err = json.Unmarshal([]byte(value), &node); err != nil {
|
||||
return count, err
|
||||
} else {
|
||||
if node.Network == networkName {
|
||||
if node.Network == networkName && node.IsServer != "yes" {
|
||||
count++
|
||||
}
|
||||
}
|
||||
@@ -491,12 +486,6 @@ func IsIpCIDR(host string) bool {
|
||||
return ip != nil && ipnet != nil
|
||||
}
|
||||
|
||||
//This is used to validate public keys (make sure they're base64 encoded like all public keys should be).
|
||||
func IsBase64(s string) bool {
|
||||
_, err := base64.StdEncoding.DecodeString(s)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
//This checks to make sure a network name is valid.
|
||||
//Switch to REGEX?
|
||||
func NameInNetworkCharSet(name string) bool {
|
||||
|
38
logic/extpeers.go
Normal file
38
logic/extpeers.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
)
|
||||
|
||||
func GetExtPeersList(macaddress string, networkName string) ([]models.ExtPeersResponse, error) {
|
||||
|
||||
var peers []models.ExtPeersResponse
|
||||
records, err := database.FetchRecords(database.EXT_CLIENT_TABLE_NAME)
|
||||
|
||||
if err != nil {
|
||||
return peers, err
|
||||
}
|
||||
|
||||
for _, value := range records {
|
||||
var peer models.ExtPeersResponse
|
||||
var extClient models.ExtClient
|
||||
err = json.Unmarshal([]byte(value), &peer)
|
||||
if err != nil {
|
||||
functions.PrintUserLog(models.NODE_SERVER_NAME, "failed to unmarshal peer", 2)
|
||||
continue
|
||||
}
|
||||
err = json.Unmarshal([]byte(value), &extClient)
|
||||
if err != nil {
|
||||
functions.PrintUserLog(models.NODE_SERVER_NAME, "failed to unmarshal ext client", 2)
|
||||
continue
|
||||
}
|
||||
if extClient.Network == networkName && extClient.IngressGatewayID == macaddress {
|
||||
peers = append(peers, peer)
|
||||
}
|
||||
}
|
||||
return peers, err
|
||||
}
|
88
logic/nodes.go
Normal file
88
logic/nodes.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
)
|
||||
|
||||
func GetNetworkNodes(network string) ([]models.Node, error) {
|
||||
var nodes []models.Node
|
||||
collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
|
||||
if err != nil {
|
||||
if database.IsEmptyRecord(err) {
|
||||
return []models.Node{}, nil
|
||||
}
|
||||
return nodes, err
|
||||
}
|
||||
for _, value := range collection {
|
||||
|
||||
var node models.Node
|
||||
err := json.Unmarshal([]byte(value), &node)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if node.Network == network {
|
||||
nodes = append(nodes, node)
|
||||
}
|
||||
}
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
func GetSortedNetworkServerNodes(network string) ([]models.Node, error) {
|
||||
var nodes []models.Node
|
||||
collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
|
||||
if err != nil {
|
||||
if database.IsEmptyRecord(err) {
|
||||
return []models.Node{}, nil
|
||||
}
|
||||
return nodes, err
|
||||
}
|
||||
for _, value := range collection {
|
||||
|
||||
var node models.Node
|
||||
err := json.Unmarshal([]byte(value), &node)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if node.Network == network && node.IsServer == "yes" {
|
||||
nodes = append(nodes, node)
|
||||
}
|
||||
}
|
||||
sort.Sort(models.NodesArray(nodes))
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
func GetPeers(node models.Node) ([]models.Node, error) {
|
||||
if node.IsServer == "yes" && IsLeader(&node) {
|
||||
SetNetworkServerPeers(&node)
|
||||
}
|
||||
excludeIsRelayed := node.IsRelay != "yes"
|
||||
var relayedNode string
|
||||
if node.IsRelayed == "yes" {
|
||||
relayedNode = node.Address
|
||||
}
|
||||
peers, err := GetPeersList(node.Network, excludeIsRelayed, relayedNode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return peers, nil
|
||||
}
|
||||
|
||||
func IsLeader(node *models.Node) bool {
|
||||
nodes, err := GetSortedNetworkServerNodes(node.Network)
|
||||
if err != nil {
|
||||
functions.PrintUserLog("[netmaker]", "ERROR: COULD NOT RETRIEVE SERVER NODES. THIS WILL BREAK HOLE PUNCHING.", 0)
|
||||
return false
|
||||
}
|
||||
for _, n := range nodes {
|
||||
if n.LastModified > time.Now().Add(-1*time.Minute).Unix() {
|
||||
return n.Address == node.Address
|
||||
}
|
||||
}
|
||||
return len(nodes) <= 1 || nodes[1].Address == node.Address
|
||||
}
|
285
logic/util.go
Normal file
285
logic/util.go
Normal file
@@ -0,0 +1,285 @@
|
||||
// package for logicing client and server code
|
||||
package logic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"encoding/base64"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/dnslogic"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/relay"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
//This is used to validate public keys (make sure they're base64 encoded like all public keys should be).
|
||||
func IsBase64(s string) bool {
|
||||
_, err := base64.StdEncoding.DecodeString(s)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func CheckEndpoint(endpoint string) bool {
|
||||
endpointarr := strings.Split(endpoint, ":")
|
||||
return len(endpointarr) == 2
|
||||
}
|
||||
|
||||
func SetNetworkServerPeers(node *models.Node) {
|
||||
if currentPeersList, err := GetSystemPeers(node); err == nil {
|
||||
if database.SetPeers(currentPeersList, node.Network) {
|
||||
functions.PrintUserLog(models.NODE_SERVER_NAME, "set new peers on network "+node.Network, 1)
|
||||
}
|
||||
} else {
|
||||
functions.PrintUserLog(models.NODE_SERVER_NAME, "could not set peers on network "+node.Network, 1)
|
||||
functions.PrintUserLog(models.NODE_SERVER_NAME, err.Error(), 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func DeleteNode(key string, exterminate bool) error {
|
||||
var err error
|
||||
if !exterminate {
|
||||
args := strings.Split(key, "###")
|
||||
node, err := GetNode(args[0], args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
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 {
|
||||
functions.PrintUserLog("", err.Error(), 2)
|
||||
}
|
||||
}
|
||||
if err := database.DeleteRecord(database.NODES_TABLE_NAME, key); err != nil {
|
||||
return err
|
||||
}
|
||||
if servercfg.IsDNSMode() {
|
||||
err = dnslogic.SetDNS()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
func CreateNode(node models.Node, networkName string) (models.Node, error) {
|
||||
|
||||
//encrypt that password so we never see it
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(node.Password), 5)
|
||||
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
//set password to encrypted password
|
||||
node.Password = string(hash)
|
||||
|
||||
node.Network = networkName
|
||||
if node.Name == models.NODE_SERVER_NAME {
|
||||
node.IsServer = "yes"
|
||||
}
|
||||
if servercfg.IsDNSMode() && node.DNSOn == "" {
|
||||
node.DNSOn = "yes"
|
||||
}
|
||||
node.SetDefaults()
|
||||
node.Address, err = functions.UniqueAddress(networkName)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
node.Address6, err = functions.UniqueAddress6(networkName)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
//Create a JWT for the node
|
||||
tokenString, _ := functions.CreateJWT(node.MacAddress, networkName)
|
||||
if tokenString == "" {
|
||||
//returnErrorResponse(w, r, errorResponse)
|
||||
return node, err
|
||||
}
|
||||
err = node.Validate(false)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
key, err := functions.GetRecordKey(node.MacAddress, node.Network)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
nodebytes, err := json.Marshal(&node)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
err = database.Insert(key, string(nodebytes), database.NODES_TABLE_NAME)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
if node.IsPending != "yes" {
|
||||
functions.DecrimentKey(node.Network, node.AccessKey)
|
||||
}
|
||||
SetNetworkNodesLastModified(node.Network)
|
||||
if servercfg.IsDNSMode() {
|
||||
err = dnslogic.SetDNS()
|
||||
}
|
||||
return node, err
|
||||
}
|
||||
|
||||
func SetNetworkNodesLastModified(networkName string) error {
|
||||
|
||||
timestamp := time.Now().Unix()
|
||||
|
||||
network, err := functions.GetParentNetwork(networkName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
network.NodesLastModified = timestamp
|
||||
data, err := json.Marshal(&network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = database.Insert(networkName, string(data), database.NETWORKS_TABLE_NAME)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetNode(macaddress string, network string) (models.Node, error) {
|
||||
var node models.Node
|
||||
|
||||
key, err := functions.GetRecordKey(macaddress, network)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
data, err := database.FetchRecord(database.NODES_TABLE_NAME, key)
|
||||
if err != nil {
|
||||
if data == "" {
|
||||
data, err = database.FetchRecord(database.DELETED_NODES_TABLE_NAME, key)
|
||||
err = json.Unmarshal([]byte(data), &node)
|
||||
}
|
||||
return node, err
|
||||
}
|
||||
if err = json.Unmarshal([]byte(data), &node); err != nil {
|
||||
return node, err
|
||||
}
|
||||
node.SetDefaults()
|
||||
|
||||
return node, err
|
||||
}
|
||||
|
||||
func GetNodePeers(networkName string, excludeRelayed bool) ([]models.Node, error) {
|
||||
var peers []models.Node
|
||||
collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
|
||||
if err != nil {
|
||||
if database.IsEmptyRecord(err) {
|
||||
return peers, nil
|
||||
}
|
||||
functions.PrintUserLog("", err.Error(), 2)
|
||||
return nil, err
|
||||
}
|
||||
udppeers, errN := database.GetPeers(networkName)
|
||||
if errN != nil {
|
||||
functions.PrintUserLog("", errN.Error(), 2)
|
||||
}
|
||||
for _, value := range collection {
|
||||
var node models.Node
|
||||
var peer models.Node
|
||||
err := json.Unmarshal([]byte(value), &node)
|
||||
if err != nil {
|
||||
functions.PrintUserLog("", err.Error(), 2)
|
||||
continue
|
||||
}
|
||||
if node.IsEgressGateway == "yes" { // handle egress stuff
|
||||
peer.EgressGatewayRanges = node.EgressGatewayRanges
|
||||
peer.IsEgressGateway = node.IsEgressGateway
|
||||
}
|
||||
allow := node.IsRelayed != "yes" || !excludeRelayed
|
||||
|
||||
if node.Network == networkName && node.IsPending != "yes" && allow {
|
||||
peer = setPeerInfo(node)
|
||||
if node.UDPHolePunch == "yes" && errN == nil && CheckEndpoint(udppeers[node.PublicKey]) {
|
||||
endpointstring := udppeers[node.PublicKey]
|
||||
endpointarr := strings.Split(endpointstring, ":")
|
||||
if len(endpointarr) == 2 {
|
||||
port, err := strconv.Atoi(endpointarr[1])
|
||||
if err == nil {
|
||||
peer.Endpoint = endpointarr[0]
|
||||
peer.ListenPort = int32(port)
|
||||
}
|
||||
}
|
||||
}
|
||||
if node.IsRelay == "yes" {
|
||||
network, err := models.GetNetwork(networkName)
|
||||
if err == nil {
|
||||
peer.AllowedIPs = append(peer.AllowedIPs, network.AddressRange)
|
||||
} else {
|
||||
peer.AllowedIPs = append(peer.AllowedIPs, node.RelayAddrs...)
|
||||
}
|
||||
}
|
||||
peers = append(peers, peer)
|
||||
}
|
||||
}
|
||||
|
||||
return peers, err
|
||||
}
|
||||
|
||||
func GetPeersList(networkName string, excludeRelayed bool, relayedNodeAddr string) ([]models.Node, error) {
|
||||
var peers []models.Node
|
||||
var relayNode models.Node
|
||||
var err error
|
||||
if relayedNodeAddr == "" {
|
||||
peers, err = GetNodePeers(networkName, excludeRelayed)
|
||||
|
||||
} else {
|
||||
relayNode, err = relay.GetNodeRelay(networkName, relayedNodeAddr)
|
||||
if relayNode.Address != "" {
|
||||
relayNode = setPeerInfo(relayNode)
|
||||
network, err := models.GetNetwork(networkName)
|
||||
if err == nil {
|
||||
relayNode.AllowedIPs = append(relayNode.AllowedIPs, network.AddressRange)
|
||||
} else {
|
||||
relayNode.AllowedIPs = append(relayNode.AllowedIPs, relayNode.RelayAddrs...)
|
||||
}
|
||||
nodepeers, err := GetNodePeers(networkName, false)
|
||||
if err == nil && relayNode.UDPHolePunch == "yes" {
|
||||
for _, nodepeer := range nodepeers {
|
||||
if nodepeer.Address == relayNode.Address {
|
||||
relayNode.Endpoint = nodepeer.Endpoint
|
||||
relayNode.ListenPort = nodepeer.ListenPort
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
peers = append(peers, relayNode)
|
||||
}
|
||||
}
|
||||
return peers, err
|
||||
}
|
||||
|
||||
func setPeerInfo(node models.Node) models.Node {
|
||||
var peer models.Node
|
||||
peer.RelayAddrs = node.RelayAddrs
|
||||
peer.IsRelay = node.IsRelay
|
||||
peer.IsServer = node.IsServer
|
||||
peer.IsRelayed = node.IsRelayed
|
||||
peer.PublicKey = node.PublicKey
|
||||
peer.Endpoint = node.Endpoint
|
||||
peer.LocalAddress = node.LocalAddress
|
||||
peer.ListenPort = node.ListenPort
|
||||
peer.AllowedIPs = node.AllowedIPs
|
||||
peer.UDPHolePunch = node.UDPHolePunch
|
||||
peer.Address = node.Address
|
||||
peer.Address6 = node.Address6
|
||||
peer.EgressGatewayRanges = node.EgressGatewayRanges
|
||||
peer.IsEgressGateway = node.IsEgressGateway
|
||||
peer.IngressGatewayRange = node.IngressGatewayRange
|
||||
peer.IsIngressGateway = node.IsIngressGateway
|
||||
peer.IsPending = node.IsPending
|
||||
return peer
|
||||
}
|
25
logic/wireguard.go
Normal file
25
logic/wireguard.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"golang.zx2c4.com/wireguard/wgctrl"
|
||||
)
|
||||
|
||||
func GetSystemPeers(node *models.Node) (map[string]string, error) {
|
||||
peers := make(map[string]string)
|
||||
|
||||
client, err := wgctrl.New()
|
||||
if err != nil {
|
||||
return peers, err
|
||||
}
|
||||
device, err := client.Device(node.Interface)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, peer := range device.Peers {
|
||||
if IsBase64(peer.PublicKey.String()) && peer.Endpoint != nil && CheckEndpoint(peer.Endpoint.String()) {
|
||||
peers[peer.PublicKey.String()] = peer.Endpoint.String()
|
||||
}
|
||||
}
|
||||
return peers, nil
|
||||
}
|
7
main.go
7
main.go
@@ -15,6 +15,7 @@ import (
|
||||
|
||||
controller "github.com/gravitl/netmaker/controllers"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/dnslogic"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
nodepb "github.com/gravitl/netmaker/grpc"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
@@ -81,14 +82,13 @@ func startControllers() {
|
||||
go runGRPC(&waitnetwork)
|
||||
}
|
||||
|
||||
// Run the client in goroutine locally if CLIENT_MODE is "contained"
|
||||
if servercfg.IsClientMode() == "contained" {
|
||||
if servercfg.IsClientMode() == "on" {
|
||||
waitnetwork.Add(1)
|
||||
go runClient(&waitnetwork)
|
||||
}
|
||||
|
||||
if servercfg.IsDNSMode() {
|
||||
err := controller.SetDNS()
|
||||
err := dnslogic.SetDNS()
|
||||
if err != nil {
|
||||
log.Println("error occurred initializing DNS:", err)
|
||||
}
|
||||
@@ -115,7 +115,6 @@ func startControllers() {
|
||||
|
||||
func runClient(wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
log.Println("CLIENT_MODE running as contained")
|
||||
go func() {
|
||||
for {
|
||||
if err := serverctl.HandleContainedClient(); err != nil {
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bytes"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
@@ -76,6 +76,18 @@ type Node struct {
|
||||
MTU int32 `json:"mtu" bson:"mtu" yaml:"mtu"`
|
||||
}
|
||||
|
||||
type NodesArray []Node
|
||||
|
||||
func (a NodesArray) Len() int { return len(a) }
|
||||
func (a NodesArray) Less(i, j int) bool { return isLess(a[i].Address, a[j].Address) }
|
||||
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
|
||||
}
|
||||
|
||||
func (node *Node) SetDefaultMTU() {
|
||||
if node.MTU == 0 {
|
||||
node.MTU = 1280
|
||||
@@ -263,9 +275,12 @@ func (node *Node) SetDefaults() {
|
||||
}
|
||||
}
|
||||
// == Parent Network settings ==
|
||||
node.CheckInInterval = parentNetwork.DefaultCheckInInterval
|
||||
node.IsDualStack = parentNetwork.IsDualStack
|
||||
node.MTU = parentNetwork.DefaultMTU
|
||||
if node.IsDualStack == "" {
|
||||
node.IsDualStack = parentNetwork.IsDualStack
|
||||
}
|
||||
if node.MTU == 0 {
|
||||
node.MTU = parentNetwork.DefaultMTU
|
||||
}
|
||||
// == node defaults if not set by parent ==
|
||||
node.SetIPForwardingDefault()
|
||||
node.SetDNSOnDefault()
|
||||
@@ -535,9 +550,9 @@ func GetAllNodes() ([]Node, error) {
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
func GetID(macaddress string, network string) (string, error) {
|
||||
if macaddress == "" || network == "" {
|
||||
func (node *Node) GetID() (string, error) {
|
||||
if node.MacAddress == "" || node.Network == "" {
|
||||
return "", errors.New("unable to get record key")
|
||||
}
|
||||
return macaddress + "###" + network, nil
|
||||
return node.MacAddress + "###" + node.Network, nil
|
||||
}
|
||||
|
@@ -58,7 +58,7 @@ func Join(cfg config.ClientConfig, privateKey string) error {
|
||||
|
||||
func getWindowsInterval() int {
|
||||
interval := 15
|
||||
networks, err := functions.GetNetworks()
|
||||
networks, err := ncutils.GetSystemNetworks()
|
||||
if err != nil {
|
||||
return interval
|
||||
}
|
||||
@@ -90,12 +90,13 @@ func RunUserspaceDaemon() {
|
||||
|
||||
func CheckIn(cfg config.ClientConfig) error {
|
||||
var err error
|
||||
|
||||
if cfg.Network == "" {
|
||||
ncutils.PrintLog("required, '-n', exiting", 0)
|
||||
os.Exit(1)
|
||||
} else if cfg.Network == "all" {
|
||||
ncutils.PrintLog("running checkin for all networks", 1)
|
||||
networks, err := functions.GetNetworks()
|
||||
networks, err := ncutils.GetSystemNetworks()
|
||||
if err != nil {
|
||||
ncutils.PrintLog("error retrieving networks, exiting", 1)
|
||||
return err
|
||||
@@ -138,7 +139,7 @@ func Push(cfg config.ClientConfig) error {
|
||||
var err error
|
||||
if cfg.Network == "all" || ncutils.IsWindows() {
|
||||
ncutils.PrintLog("pushing config to server for all networks.", 0)
|
||||
networks, err := functions.GetNetworks()
|
||||
networks, err := ncutils.GetSystemNetworks()
|
||||
if err != nil {
|
||||
ncutils.PrintLog("error retrieving networks, exiting.", 0)
|
||||
return err
|
||||
@@ -164,7 +165,7 @@ func Pull(cfg config.ClientConfig) error {
|
||||
var err error
|
||||
if cfg.Network == "all" {
|
||||
ncutils.PrintLog("No network selected. Running Pull for all networks.", 0)
|
||||
networks, err := functions.GetNetworks()
|
||||
networks, err := ncutils.GetSystemNetworks()
|
||||
if err != nil {
|
||||
ncutils.PrintLog("Error retrieving networks. Exiting.", 1)
|
||||
return err
|
||||
|
@@ -1,12 +1,15 @@
|
||||
package functions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
nodepb "github.com/gravitl/netmaker/grpc"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/netclient/auth"
|
||||
"github.com/gravitl/netmaker/netclient/config"
|
||||
@@ -136,7 +139,6 @@ func CheckConfig(cliconf config.ClientConfig) error {
|
||||
if newNode.IsPending == "yes" {
|
||||
return errors.New("node is pending")
|
||||
}
|
||||
|
||||
actionCompleted := checkNodeActions(newNode, network, servercfg, ¤tNode, cfg)
|
||||
if actionCompleted == models.NODE_DELETE {
|
||||
return errors.New("node has been removed")
|
||||
@@ -164,32 +166,40 @@ func Pull(network string, manual bool) (*models.Node, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
|
||||
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
|
||||
if err != nil {
|
||||
ncutils.PrintLog("Cant dial GRPC server: "+err.Error(), 1)
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
wcclient := nodepb.NewNodeServiceClient(conn)
|
||||
var resNode models.Node // just need to fill this with either server calls or client calls
|
||||
var ctx context.Context
|
||||
if cfg.Node.IsServer != "yes" {
|
||||
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
|
||||
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
|
||||
if err != nil {
|
||||
ncutils.PrintLog("Cant dial GRPC server: "+err.Error(), 1)
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
wcclient := nodepb.NewNodeServiceClient(conn)
|
||||
|
||||
ctx, err := auth.SetJWT(wcclient, network)
|
||||
if err != nil {
|
||||
ncutils.PrintLog("Failed to authenticate: "+err.Error(), 1)
|
||||
return nil, err
|
||||
}
|
||||
ctx, err := auth.SetJWT(wcclient, network)
|
||||
if err != nil {
|
||||
ncutils.PrintLog("Failed to authenticate: "+err.Error(), 1)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := &nodepb.Object{
|
||||
Data: node.MacAddress + "###" + node.Network,
|
||||
Type: nodepb.STRING_TYPE,
|
||||
}
|
||||
readres, err := wcclient.ReadNode(ctx, req, grpc.Header(&header))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var resNode models.Node
|
||||
if err = json.Unmarshal([]byte(readres.Data), &resNode); err != nil {
|
||||
return nil, err
|
||||
req := &nodepb.Object{
|
||||
Data: node.MacAddress + "###" + node.Network,
|
||||
Type: nodepb.STRING_TYPE,
|
||||
}
|
||||
readres, err := wcclient.ReadNode(ctx, req, grpc.Header(&header))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = json.Unmarshal([]byte(readres.Data), &resNode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else { // handle server side read
|
||||
resNode, err = logic.GetNode(node.MacAddress, node.Network)
|
||||
if err != nil && !ncutils.IsEmptyRecord(err) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// ensure that the OS never changes
|
||||
resNode.OS = runtime.GOOS
|
||||
@@ -211,14 +221,20 @@ func Pull(network string, manual bool) (*models.Node, error) {
|
||||
if err != nil {
|
||||
return &resNode, err
|
||||
}
|
||||
req := &nodepb.Object{
|
||||
Data: string(nodeData),
|
||||
Type: nodepb.NODE_TYPE,
|
||||
Metadata: "",
|
||||
}
|
||||
_, err = wcclient.UpdateNode(ctx, req, grpc.Header(&header))
|
||||
if err != nil {
|
||||
return &resNode, err
|
||||
if resNode.IsServer != "yes" {
|
||||
req := &nodepb.Object{
|
||||
Data: string(nodeData),
|
||||
Type: nodepb.NODE_TYPE,
|
||||
Metadata: "",
|
||||
}
|
||||
_, err = wcclient.UpdateNode(ctx, req, grpc.Header(&header))
|
||||
if err != nil {
|
||||
return &resNode, err
|
||||
}
|
||||
} else { // handle server side update
|
||||
if err = resNode.Update(&resNode); err != nil {
|
||||
return &resNode, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err = wireguard.SetWGConfig(network, true); err != nil {
|
||||
@@ -244,54 +260,60 @@ func Push(network string) error {
|
||||
postnode := cfg.Node
|
||||
// always set the OS on client
|
||||
postnode.OS = runtime.GOOS
|
||||
var header metadata.MD
|
||||
|
||||
var wcclient nodepb.NodeServiceClient
|
||||
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
|
||||
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
|
||||
if err != nil {
|
||||
ncutils.PrintLog("Cant dial GRPC server: "+err.Error(), 1)
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
wcclient = nodepb.NewNodeServiceClient(conn)
|
||||
|
||||
ctx, err := auth.SetJWT(wcclient, network)
|
||||
if err != nil {
|
||||
ncutils.PrintLog("Failed to authenticate with server: "+err.Error(), 1)
|
||||
return err
|
||||
}
|
||||
if postnode.IsPending != "yes" {
|
||||
privateKey, err := wireguard.RetrievePrivKey(network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
privateKeyWG, err := wgtypes.ParseKey(privateKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if postnode.PublicKey != privateKeyWG.PublicKey().String() {
|
||||
postnode.PublicKey = privateKeyWG.PublicKey().String()
|
||||
}
|
||||
}
|
||||
postnode.SetLastCheckIn()
|
||||
nodeData, err := json.Marshal(&postnode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req := &nodepb.Object{
|
||||
Data: string(nodeData),
|
||||
Type: nodepb.NODE_TYPE,
|
||||
Metadata: "",
|
||||
}
|
||||
data, err := wcclient.UpdateNode(ctx, req, grpc.Header(&header))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal([]byte(data.Data), &postnode)
|
||||
if err != nil {
|
||||
return err
|
||||
if postnode.IsServer != "yes" { // handle client side
|
||||
var header metadata.MD
|
||||
var wcclient nodepb.NodeServiceClient
|
||||
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
|
||||
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
|
||||
if err != nil {
|
||||
ncutils.PrintLog("Cant dial GRPC server: "+err.Error(), 1)
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
wcclient = nodepb.NewNodeServiceClient(conn)
|
||||
|
||||
ctx, err := auth.SetJWT(wcclient, network)
|
||||
if err != nil {
|
||||
ncutils.PrintLog("Failed to authenticate with server: "+err.Error(), 1)
|
||||
return err
|
||||
}
|
||||
if postnode.IsPending != "yes" {
|
||||
privateKey, err := wireguard.RetrievePrivKey(network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
privateKeyWG, err := wgtypes.ParseKey(privateKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if postnode.PublicKey != privateKeyWG.PublicKey().String() {
|
||||
postnode.PublicKey = privateKeyWG.PublicKey().String()
|
||||
}
|
||||
}
|
||||
nodeData, err := json.Marshal(&postnode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req := &nodepb.Object{
|
||||
Data: string(nodeData),
|
||||
Type: nodepb.NODE_TYPE,
|
||||
Metadata: "",
|
||||
}
|
||||
data, err := wcclient.UpdateNode(ctx, req, grpc.Header(&header))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal([]byte(data.Data), &postnode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err = postnode.Update(&postnode); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = config.ModConfig(&postnode)
|
||||
return err
|
||||
|
@@ -5,7 +5,6 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
@@ -13,6 +12,7 @@ import (
|
||||
"strings"
|
||||
|
||||
nodepb "github.com/gravitl/netmaker/grpc"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/netclient/auth"
|
||||
"github.com/gravitl/netmaker/netclient/config"
|
||||
@@ -138,7 +138,7 @@ func GetNode(network string) models.Node {
|
||||
}
|
||||
|
||||
func Uninstall() error {
|
||||
networks, err := GetNetworks()
|
||||
networks, err := ncutils.GetSystemNetworks()
|
||||
if err != nil {
|
||||
ncutils.PrintLog("unable to retrieve networks: "+err.Error(), 1)
|
||||
ncutils.PrintLog("continuing uninstall without leaving networks", 1)
|
||||
@@ -163,7 +163,6 @@ func Uninstall() error {
|
||||
}
|
||||
|
||||
func LeaveNetwork(network string) error {
|
||||
//need to implement checkin on server side
|
||||
cfg, err := config.ReadConfig(network)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -171,19 +170,20 @@ func LeaveNetwork(network string) error {
|
||||
servercfg := cfg.Server
|
||||
node := cfg.Node
|
||||
|
||||
var wcclient nodepb.NodeServiceClient
|
||||
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
|
||||
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
|
||||
if err != nil {
|
||||
log.Printf("Unable to establish client connection to "+servercfg.GRPCAddress+": %v", err)
|
||||
} else {
|
||||
if node.IsServer != "yes" {
|
||||
var wcclient nodepb.NodeServiceClient
|
||||
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
|
||||
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
|
||||
if err != nil {
|
||||
log.Printf("Unable to establish client connection to "+servercfg.GRPCAddress+": %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
wcclient = nodepb.NewNodeServiceClient(conn)
|
||||
|
||||
ctx, err := auth.SetJWT(wcclient, network)
|
||||
if err != nil {
|
||||
log.Printf("Failed to authenticate: %v", err)
|
||||
} else {
|
||||
} else { // handle client side
|
||||
node.SetID()
|
||||
var header metadata.MD
|
||||
_, err = wcclient.DeleteNode(
|
||||
@@ -200,6 +200,13 @@ func LeaveNetwork(network string) error {
|
||||
ncutils.PrintLog("removed machine from "+node.Network+" network on remote server", 1)
|
||||
}
|
||||
}
|
||||
} else { // handle server side
|
||||
node.SetID()
|
||||
if err = logic.DeleteNode(node.ID, true); err != nil {
|
||||
ncutils.PrintLog("error removing server on network "+node.Network, 1)
|
||||
} else {
|
||||
ncutils.PrintLog("removed netmaker server instance on "+node.Network, 1)
|
||||
}
|
||||
}
|
||||
return RemoveLocalInstance(cfg, network)
|
||||
}
|
||||
@@ -244,7 +251,7 @@ func DeleteInterface(ifacename string, postdown string) error {
|
||||
|
||||
func List() error {
|
||||
|
||||
networks, err := GetNetworks()
|
||||
networks, err := ncutils.GetSystemNetworks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -267,34 +274,6 @@ func List() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetNetworks() ([]string, error) {
|
||||
var networks []string
|
||||
files, err := ioutil.ReadDir(ncutils.GetNetclientPathSpecific())
|
||||
if err != nil {
|
||||
return networks, err
|
||||
}
|
||||
for _, f := range files {
|
||||
if strings.Contains(f.Name(), "netconfig-") {
|
||||
networkname := stringAfter(f.Name(), "netconfig-")
|
||||
networks = append(networks, networkname)
|
||||
}
|
||||
}
|
||||
return networks, err
|
||||
}
|
||||
|
||||
func stringAfter(original string, substring string) string {
|
||||
position := strings.LastIndex(original, substring)
|
||||
if position == -1 {
|
||||
return ""
|
||||
}
|
||||
adjustedPosition := position + len(substring)
|
||||
|
||||
if adjustedPosition >= len(original) {
|
||||
return ""
|
||||
}
|
||||
return original[adjustedPosition:len(original)]
|
||||
}
|
||||
|
||||
func WipeLocal(network string) error {
|
||||
cfg, err := config.ReadConfig(network)
|
||||
if err != nil {
|
||||
@@ -302,7 +281,6 @@ func WipeLocal(network string) error {
|
||||
}
|
||||
nodecfg := cfg.Node
|
||||
ifacename := nodecfg.Interface
|
||||
|
||||
if ifacename != "" {
|
||||
if !ncutils.IsKernel() {
|
||||
if err = wireguard.RemoveConf(ifacename, true); err == nil {
|
||||
|
@@ -8,6 +8,7 @@ import (
|
||||
"log"
|
||||
|
||||
nodepb "github.com/gravitl/netmaker/grpc"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/netclient/auth"
|
||||
"github.com/gravitl/netmaker/netclient/config"
|
||||
@@ -28,7 +29,6 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
ncutils.Log("joining " + cfg.Network + " at " + cfg.Server.GRPCAddress)
|
||||
err := config.Write(&cfg, cfg.Network)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -53,7 +53,6 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
|
||||
cfg.Node.Endpoint = cfg.Node.LocalAddress
|
||||
} else {
|
||||
cfg.Node.Endpoint, err = ncutils.GetPublicIP()
|
||||
|
||||
}
|
||||
if err != nil || cfg.Node.Endpoint == "" {
|
||||
ncutils.Log("Error setting cfg.Node.Endpoint.")
|
||||
@@ -82,17 +81,8 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
|
||||
}
|
||||
}
|
||||
|
||||
var wcclient nodepb.NodeServiceClient
|
||||
|
||||
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
|
||||
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to establish client connection to "+cfg.Server.GRPCAddress+": %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
wcclient = nodepb.NewNodeServiceClient(conn)
|
||||
|
||||
// differentiate between client/server here
|
||||
var node models.Node // fill this node with appropriate calls
|
||||
postnode := &models.Node{
|
||||
Password: cfg.Node.Password,
|
||||
MacAddress: cfg.Node.MacAddress,
|
||||
@@ -105,37 +95,63 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
|
||||
LocalAddress: cfg.Node.LocalAddress,
|
||||
Interface: cfg.Node.Interface,
|
||||
PublicKey: cfg.Node.PublicKey,
|
||||
DNSOn: cfg.Node.DNSOn,
|
||||
DNSOn: cfg.Node.DNSOn,
|
||||
Name: cfg.Node.Name,
|
||||
Endpoint: cfg.Node.Endpoint,
|
||||
SaveConfig: cfg.Node.SaveConfig,
|
||||
UDPHolePunch: cfg.Node.UDPHolePunch,
|
||||
}
|
||||
|
||||
if err = config.ModConfig(postnode); err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := json.Marshal(postnode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Create node on server
|
||||
res, err := wcclient.CreateNode(
|
||||
context.TODO(),
|
||||
&nodepb.Object{
|
||||
Data: string(data),
|
||||
Type: nodepb.NODE_TYPE,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ncutils.PrintLog("node created on remote server...updating configs", 1)
|
||||
if cfg.Node.IsServer != "yes" {
|
||||
ncutils.Log("joining " + cfg.Network + " at " + cfg.Server.GRPCAddress)
|
||||
var wcclient nodepb.NodeServiceClient
|
||||
|
||||
nodeData := res.Data
|
||||
var node models.Node
|
||||
if err = json.Unmarshal([]byte(nodeData), &node); err != nil {
|
||||
return err
|
||||
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
|
||||
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to establish client connection to "+cfg.Server.GRPCAddress+": %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
wcclient = nodepb.NewNodeServiceClient(conn)
|
||||
|
||||
if err = config.ModConfig(postnode); err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := json.Marshal(postnode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Create node on server
|
||||
res, err := wcclient.CreateNode(
|
||||
context.TODO(),
|
||||
&nodepb.Object{
|
||||
Data: string(data),
|
||||
Type: nodepb.NODE_TYPE,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ncutils.PrintLog("node created on remote server...updating configs", 1)
|
||||
|
||||
nodeData := res.Data
|
||||
if err = json.Unmarshal([]byte(nodeData), &node); err != nil {
|
||||
return err
|
||||
}
|
||||
} else { // handle server side node creation
|
||||
ncutils.Log("adding a server instance on network " + postnode.Network)
|
||||
if err = config.ModConfig(postnode); err != nil {
|
||||
return err
|
||||
}
|
||||
node, err = logic.CreateNode(*postnode, cfg.Network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = logic.SetNetworkNodesLastModified(node.Network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// get free port based on returned default listen port
|
||||
@@ -177,9 +193,8 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
|
||||
}
|
||||
}
|
||||
|
||||
ncutils.Log("retrieving remote peers")
|
||||
peers, hasGateway, gateways, err := server.GetPeers(node.MacAddress, cfg.Network, cfg.Server.GRPCAddress, node.IsDualStack == "yes", node.IsIngressGateway == "yes")
|
||||
|
||||
ncutils.Log("retrieving peers")
|
||||
peers, hasGateway, gateways, err := server.GetPeers(node.MacAddress, cfg.Network, cfg.Server.GRPCAddress, node.IsDualStack == "yes", node.IsIngressGateway == "yes", node.IsServer == "yes")
|
||||
if err != nil && !ncutils.IsEmptyRecord(err) {
|
||||
ncutils.Log("failed to retrieve peers")
|
||||
return err
|
||||
|
@@ -24,7 +24,7 @@ func main() {
|
||||
app := cli.NewApp()
|
||||
app.Name = "Netclient CLI"
|
||||
app.Usage = "Netmaker's netclient agent and CLI. Used to perform interactions with Netmaker server and set local WireGuard config."
|
||||
app.Version = "v0.8.1"
|
||||
app.Version = "v0.8.3"
|
||||
|
||||
cliFlags := []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
|
@@ -368,3 +368,31 @@ func PrintLog(message string, loglevel int) {
|
||||
log.Println("[netclient]", message)
|
||||
}
|
||||
}
|
||||
|
||||
func GetSystemNetworks() ([]string, error) {
|
||||
var networks []string
|
||||
files, err := ioutil.ReadDir(GetNetclientPathSpecific())
|
||||
if err != nil {
|
||||
return networks, err
|
||||
}
|
||||
for _, f := range files {
|
||||
if strings.Contains(f.Name(), "netconfig-") {
|
||||
networkname := stringAfter(f.Name(), "netconfig-")
|
||||
networks = append(networks, networkname)
|
||||
}
|
||||
}
|
||||
return networks, err
|
||||
}
|
||||
|
||||
func stringAfter(original string, substring string) string {
|
||||
position := strings.LastIndex(original, substring)
|
||||
if position == -1 {
|
||||
return ""
|
||||
}
|
||||
adjustedPosition := position + len(substring)
|
||||
|
||||
if adjustedPosition >= len(original) {
|
||||
return ""
|
||||
}
|
||||
return original[adjustedPosition:len(original)]
|
||||
}
|
@@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
nodepb "github.com/gravitl/netmaker/grpc"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/netclient/auth"
|
||||
"github.com/gravitl/netmaker/netclient/config"
|
||||
@@ -40,30 +41,32 @@ func CheckIn(network string) (*models.Node, error) {
|
||||
return nil, err
|
||||
}
|
||||
node := cfg.Node
|
||||
wcclient, err := getGrpcClient(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// == run client action ==
|
||||
var header metadata.MD
|
||||
ctx, err := auth.SetJWT(wcclient, network)
|
||||
nodeData, err := json.Marshal(&node)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response, err := wcclient.ReadNode(
|
||||
ctx,
|
||||
&nodepb.Object{
|
||||
Data: string(nodeData),
|
||||
Type: nodepb.NODE_TYPE,
|
||||
},
|
||||
grpc.Header(&header),
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Encountered error checking in node: %v", err)
|
||||
}
|
||||
if err = json.Unmarshal([]byte(response.GetData()), &node); err != nil {
|
||||
return nil, err
|
||||
if cfg.Node.IsServer != "yes" {
|
||||
wcclient, err := getGrpcClient(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// == run client action ==
|
||||
var header metadata.MD
|
||||
ctx, err := auth.SetJWT(wcclient, network)
|
||||
nodeData, err := json.Marshal(&node)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response, err := wcclient.ReadNode(
|
||||
ctx,
|
||||
&nodepb.Object{
|
||||
Data: string(nodeData),
|
||||
Type: nodepb.NODE_TYPE,
|
||||
},
|
||||
grpc.Header(&header),
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Encountered error checking in node: %v", err)
|
||||
}
|
||||
if err = json.Unmarshal([]byte(response.GetData()), &node); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &node, err
|
||||
}
|
||||
@@ -116,11 +119,11 @@ func RemoveNetwork(network string) error {
|
||||
return err
|
||||
}
|
||||
*/
|
||||
func GetPeers(macaddress string, network string, server string, dualstack bool, isIngressGateway bool) ([]wgtypes.PeerConfig, bool, []string, error) {
|
||||
|
||||
func GetPeers(macaddress string, network string, server string, dualstack bool, isIngressGateway bool, isServer bool) ([]wgtypes.PeerConfig, bool, []string, error) {
|
||||
hasGateway := false
|
||||
var gateways []string
|
||||
var peers []wgtypes.PeerConfig
|
||||
var wcclient nodepb.NodeServiceClient
|
||||
cfg, err := config.ReadConfig(network)
|
||||
if err != nil {
|
||||
log.Fatalf("Issue retrieving config for network: "+network+". Please investigate: %v", err)
|
||||
@@ -132,40 +135,48 @@ func GetPeers(macaddress string, network string, server string, dualstack bool,
|
||||
if err != nil {
|
||||
log.Fatalf("Issue with format of keepalive value. Please update netconfig: %v", err)
|
||||
}
|
||||
var nodes []models.Node // fill this either from server or client
|
||||
if !isServer { // set peers client side
|
||||
var wcclient nodepb.NodeServiceClient
|
||||
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
|
||||
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
|
||||
|
||||
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
|
||||
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to establish client connection to localhost:50051: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
// Instantiate the BlogServiceClient with our client connection to the server
|
||||
wcclient = nodepb.NewNodeServiceClient(conn)
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to establish client connection to localhost:50051: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
// Instantiate the BlogServiceClient with our client connection to the server
|
||||
wcclient = nodepb.NewNodeServiceClient(conn)
|
||||
req := &nodepb.Object{
|
||||
Data: macaddress + "###" + network,
|
||||
Type: nodepb.STRING_TYPE,
|
||||
}
|
||||
|
||||
req := &nodepb.Object{
|
||||
Data: macaddress + "###" + network,
|
||||
Type: nodepb.STRING_TYPE,
|
||||
ctx, err := auth.SetJWT(wcclient, network)
|
||||
if err != nil {
|
||||
log.Println("Failed to authenticate.")
|
||||
return peers, hasGateway, gateways, err
|
||||
}
|
||||
var header metadata.MD
|
||||
|
||||
response, err := wcclient.GetPeers(ctx, req, grpc.Header(&header))
|
||||
if err != nil {
|
||||
log.Println("Error retrieving peers")
|
||||
log.Println(err)
|
||||
return nil, hasGateway, gateways, err
|
||||
}
|
||||
if err := json.Unmarshal([]byte(response.GetData()), &nodes); err != nil {
|
||||
log.Println("Error unmarshaling data for peers")
|
||||
return nil, hasGateway, gateways, err
|
||||
}
|
||||
} else { // set peers serverside
|
||||
nodes, err = logic.GetPeers(nodecfg)
|
||||
if err != nil {
|
||||
return nil, hasGateway, gateways, err
|
||||
}
|
||||
}
|
||||
|
||||
ctx, err := auth.SetJWT(wcclient, network)
|
||||
if err != nil {
|
||||
log.Println("Failed to authenticate.")
|
||||
return peers, hasGateway, gateways, err
|
||||
}
|
||||
var header metadata.MD
|
||||
|
||||
response, err := wcclient.GetPeers(ctx, req, grpc.Header(&header))
|
||||
if err != nil {
|
||||
log.Println("Error retrieving peers")
|
||||
log.Println(err)
|
||||
return nil, hasGateway, gateways, err
|
||||
}
|
||||
var nodes []models.Node
|
||||
if err := json.Unmarshal([]byte(response.GetData()), &nodes); err != nil {
|
||||
log.Println("Error unmarshaling data for peers")
|
||||
return nil, hasGateway, gateways, err
|
||||
}
|
||||
for _, node := range nodes {
|
||||
pubkey, err := wgtypes.ParseKey(node.PublicKey)
|
||||
if err != nil {
|
||||
@@ -240,7 +251,7 @@ func GetPeers(macaddress string, network string, server string, dualstack bool,
|
||||
}
|
||||
allowedips = append(allowedips, addr6)
|
||||
}
|
||||
if nodecfg.IsServer == "yes" {
|
||||
if nodecfg.IsServer == "yes" && !(node.IsServer == "yes"){
|
||||
peer = wgtypes.PeerConfig{
|
||||
PublicKey: pubkey,
|
||||
PersistentKeepaliveInterval: &keepaliveserver,
|
||||
@@ -283,43 +294,62 @@ func GetPeers(macaddress string, network string, server string, dualstack bool,
|
||||
}
|
||||
func GetExtPeers(macaddress string, network string, server string, dualstack bool) ([]wgtypes.PeerConfig, error) {
|
||||
var peers []wgtypes.PeerConfig
|
||||
var wcclient nodepb.NodeServiceClient
|
||||
|
||||
cfg, err := config.ReadConfig(network)
|
||||
if err != nil {
|
||||
log.Fatalf("Issue retrieving config for network: "+network+". Please investigate: %v", err)
|
||||
}
|
||||
nodecfg := cfg.Node
|
||||
|
||||
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
|
||||
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to establish client connection to localhost:50051: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
// Instantiate the BlogServiceClient with our client connection to the server
|
||||
wcclient = nodepb.NewNodeServiceClient(conn)
|
||||
|
||||
req := &nodepb.Object{
|
||||
Data: macaddress + "###" + network,
|
||||
Type: nodepb.STRING_TYPE,
|
||||
}
|
||||
|
||||
ctx, err := auth.SetJWT(wcclient, network)
|
||||
if err != nil {
|
||||
log.Println("Failed to authenticate.")
|
||||
return peers, err
|
||||
}
|
||||
var header metadata.MD
|
||||
|
||||
responseObject, err := wcclient.GetExtPeers(ctx, req, grpc.Header(&header))
|
||||
if err != nil {
|
||||
log.Println("Error retrieving peers")
|
||||
log.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
var extPeers []models.Node
|
||||
if err = json.Unmarshal([]byte(responseObject.Data), &extPeers); err != nil {
|
||||
return nil, err
|
||||
if nodecfg.IsServer != "yes" { // fill extPeers with client side logic
|
||||
var wcclient nodepb.NodeServiceClient
|
||||
|
||||
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
|
||||
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to establish client connection to localhost:50051: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
// Instantiate the BlogServiceClient with our client connection to the server
|
||||
wcclient = nodepb.NewNodeServiceClient(conn)
|
||||
|
||||
req := &nodepb.Object{
|
||||
Data: macaddress + "###" + network,
|
||||
Type: nodepb.STRING_TYPE,
|
||||
}
|
||||
|
||||
ctx, err := auth.SetJWT(wcclient, network)
|
||||
if err != nil {
|
||||
log.Println("Failed to authenticate.")
|
||||
return peers, err
|
||||
}
|
||||
var header metadata.MD
|
||||
|
||||
responseObject, err := wcclient.GetExtPeers(ctx, req, grpc.Header(&header))
|
||||
if err != nil {
|
||||
log.Println("Error retrieving peers")
|
||||
log.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
if err = json.Unmarshal([]byte(responseObject.Data), &extPeers); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else { // fill extPeers with server side logic
|
||||
tempPeers, err := logic.GetExtPeersList(nodecfg.MacAddress, nodecfg.Network)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < len(tempPeers); i++ {
|
||||
extPeers = append(extPeers, models.Node{
|
||||
Address: tempPeers[i].Address,
|
||||
Address6: tempPeers[i].Address6,
|
||||
Endpoint: tempPeers[i].Endpoint,
|
||||
PublicKey: tempPeers[i].PublicKey,
|
||||
PersistentKeepalive: tempPeers[i].KeepAlive,
|
||||
ListenPort: tempPeers[i].ListenPort,
|
||||
LocalAddress: tempPeers[i].LocalAddress,
|
||||
})
|
||||
}
|
||||
}
|
||||
for _, extPeer := range extPeers {
|
||||
pubkey, err := wgtypes.ParseKey(extPeer.PublicKey)
|
||||
|
@@ -267,7 +267,7 @@ func SetWGConfig(network string, peerupdate bool) error {
|
||||
servercfg := cfg.Server
|
||||
nodecfg := cfg.Node
|
||||
|
||||
peers, hasGateway, gateways, err := server.GetPeers(nodecfg.MacAddress, nodecfg.Network, servercfg.GRPCAddress, nodecfg.IsDualStack == "yes", nodecfg.IsIngressGateway == "yes")
|
||||
peers, hasGateway, gateways, err := server.GetPeers(nodecfg.MacAddress, nodecfg.Network, servercfg.GRPCAddress, nodecfg.IsDualStack == "yes", nodecfg.IsIngressGateway == "yes", nodecfg.IsServer == "yes")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
37
relay/relay.go
Normal file
37
relay/relay.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package relay
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
)
|
||||
|
||||
func GetNodeRelay(network string, relayedNodeAddr string) (models.Node, error) {
|
||||
collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
|
||||
var relay models.Node
|
||||
if err != nil {
|
||||
if database.IsEmptyRecord(err) {
|
||||
return relay, nil
|
||||
}
|
||||
functions.PrintUserLog("", err.Error(), 2)
|
||||
return relay, err
|
||||
}
|
||||
for _, value := range collection {
|
||||
err := json.Unmarshal([]byte(value), &relay)
|
||||
if err != nil {
|
||||
functions.PrintUserLog("", err.Error(), 2)
|
||||
continue
|
||||
}
|
||||
if relay.IsRelay == "yes" {
|
||||
for _, addr := range relay.RelayAddrs {
|
||||
if addr == relayedNodeAddr {
|
||||
return relay, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return relay, errors.New("could not find relay for node " + relayedNodeAddr)
|
||||
}
|
@@ -74,7 +74,7 @@ func GetAPIConnString() string {
|
||||
return conn
|
||||
}
|
||||
func GetVersion() string {
|
||||
version := "0.8.1"
|
||||
version := "0.8.3"
|
||||
if config.Config.Server.Version != "" {
|
||||
version = config.Config.Server.Version
|
||||
}
|
||||
|
@@ -6,11 +6,11 @@ import (
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
nccommand "github.com/gravitl/netmaker/netclient/command"
|
||||
"github.com/gravitl/netmaker/netclient/config"
|
||||
"github.com/gravitl/netmaker/netclient/ncutils"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
)
|
||||
@@ -91,18 +91,8 @@ func copy(src, dst string) (int64, error) {
|
||||
}
|
||||
|
||||
func RemoveNetwork(network string) (bool, error) {
|
||||
netclientPath := ncutils.GetNetclientPath()
|
||||
_, err := os.Stat(netclientPath + "/netclient")
|
||||
if err != nil {
|
||||
log.Println("could not find " + netclientPath + "/netclient")
|
||||
return false, err
|
||||
}
|
||||
_, err = ncutils.RunCmd(netclientPath+"/netclient leave -n "+network, true)
|
||||
if err == nil {
|
||||
log.Println("Server removed from network " + network)
|
||||
}
|
||||
err := nccommand.Leave(config.ClientConfig{Network: network})
|
||||
return true, err
|
||||
|
||||
}
|
||||
|
||||
func InitServerNetclient() error {
|
||||
@@ -114,82 +104,89 @@ func InitServerNetclient() error {
|
||||
log.Println("could not find or create", netclientDir)
|
||||
return err
|
||||
}
|
||||
_, err = os.Stat(netclientDir + "/netclient")
|
||||
if os.IsNotExist(err) {
|
||||
err = InstallNetclient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = os.Chmod(netclientDir+"/netclient", 0755)
|
||||
if err != nil {
|
||||
log.Println("could not change netclient binary permissions")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func HandleContainedClient() error {
|
||||
log.SetFlags(log.Flags() &^ (log.Llongfile | log.Lshortfile))
|
||||
servernets, err := models.GetNetworks()
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return err
|
||||
}
|
||||
if len(servernets) > 0 {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.SetFlags(log.Flags() &^ (log.Llongfile | log.Lshortfile))
|
||||
err := SyncNetworks(servernets)
|
||||
if err != nil && servercfg.GetVerbose() >= 1 {
|
||||
log.Printf("[server netclient] error syncing networks %s \n", err)
|
||||
}
|
||||
err = nccommand.CheckIn(config.ClientConfig{Network: "all"})
|
||||
if err != nil && servercfg.GetVerbose() >= 1 {
|
||||
log.Printf("[server netclient] error occurred %s \n", err)
|
||||
}
|
||||
if servercfg.GetVerbose() >= 3 {
|
||||
log.Println("[server netclient]", "completed a checkin call")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
netclientPath := ncutils.GetNetclientPath()
|
||||
checkinCMD := exec.Command(netclientPath+"/netclient", "checkin", "-n", "all")
|
||||
if servercfg.GetVerbose() >= 2 {
|
||||
checkinCMD.Stdout = os.Stdout
|
||||
}
|
||||
checkinCMD.Stderr = os.Stderr
|
||||
err := checkinCMD.Start()
|
||||
func SyncNetworks(servernets []models.Network) error {
|
||||
|
||||
localnets, err := ncutils.GetSystemNetworks()
|
||||
if err != nil {
|
||||
if servercfg.GetVerbose() >= 2 {
|
||||
log.Println(err)
|
||||
return err
|
||||
}
|
||||
// check networks to join
|
||||
for _, servernet := range servernets {
|
||||
exists := false
|
||||
for _, localnet := range localnets {
|
||||
if servernet.NetID == localnet {
|
||||
exists = true
|
||||
}
|
||||
}
|
||||
if !exists {
|
||||
success, err := AddNetwork(servernet.NetID)
|
||||
if err != nil || !success {
|
||||
if err == nil {
|
||||
err = errors.New("network add failed for " + servernet.NetID)
|
||||
}
|
||||
log.Printf("[server] error adding network %s during sync %s \n", servernet.NetID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
err = checkinCMD.Wait()
|
||||
if err != nil {
|
||||
if servercfg.GetVerbose() >= 2 {
|
||||
log.Println(err)
|
||||
// check networks to leave
|
||||
for _, localnet := range localnets {
|
||||
exists := false
|
||||
for _, servernet := range servernets {
|
||||
if servernet.NetID == localnet {
|
||||
exists = true
|
||||
}
|
||||
}
|
||||
if !exists {
|
||||
success, err := RemoveNetwork(localnet)
|
||||
if err != nil || !success {
|
||||
if err == nil {
|
||||
err = errors.New("network delete failed for " + localnet)
|
||||
}
|
||||
log.Printf("[server] error removing network %s during sync %s \n", localnet, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if servercfg.GetVerbose() >= 3 {
|
||||
log.Println("[server netclient]", "completed a checkin call")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func AddNetwork(network string) (bool, error) {
|
||||
pubip, err := servercfg.GetPublicIP()
|
||||
if err != nil {
|
||||
log.Println("could not get public IP.")
|
||||
return false, err
|
||||
}
|
||||
netclientPath := ncutils.GetNetclientPath()
|
||||
|
||||
token, err := functions.CreateServerToken(network)
|
||||
if err != nil {
|
||||
log.Println("could not create server token for " + network)
|
||||
return false, err
|
||||
}
|
||||
|
||||
functions.PrintUserLog(models.NODE_SERVER_NAME, "executing network join: "+netclientPath+"netclient "+"join "+"-t "+token+" -name "+models.NODE_SERVER_NAME+" -endpoint "+pubip, 0)
|
||||
var joinCMD *exec.Cmd
|
||||
if servercfg.IsClientMode() == "contained" {
|
||||
joinCMD = exec.Command(netclientPath+"/netclient", "join", "-t", token, "-name", models.NODE_SERVER_NAME, "-endpoint", pubip, "-daemon", "off", "-dnson", "no")
|
||||
} else {
|
||||
joinCMD = exec.Command(netclientPath+"/netclient", "join", "-t", token, "-name", models.NODE_SERVER_NAME, "-endpoint", pubip)
|
||||
}
|
||||
joinCMD.Stdout = os.Stdout
|
||||
joinCMD.Stderr = os.Stderr
|
||||
err = joinCMD.Start()
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
log.Println("Waiting for join command to finish...")
|
||||
err = joinCMD.Wait()
|
||||
if err != nil {
|
||||
log.Printf("Command finished with error: %v", err)
|
||||
return false, err
|
||||
}
|
||||
err := nccommand.Join(config.ClientConfig{
|
||||
Network: network,
|
||||
Daemon: "off",
|
||||
Node: models.Node{
|
||||
Network: network,
|
||||
IsServer: "yes",
|
||||
Name: models.NODE_SERVER_NAME,
|
||||
},
|
||||
}, "")
|
||||
log.Println("Server added to network " + network)
|
||||
return true, err
|
||||
}
|
||||
|
@@ -1,30 +0,0 @@
|
||||
package serverctl
|
||||
|
||||
import (
|
||||
"github.com/gravitl/netmaker/functions"
|
||||
"golang.zx2c4.com/wireguard/wgctrl"
|
||||
)
|
||||
|
||||
func GetPeers(networkName string) (map[string]string, error) {
|
||||
peers := make(map[string]string)
|
||||
network, err := functions.GetParentNetwork(networkName)
|
||||
if err != nil {
|
||||
return peers, err
|
||||
}
|
||||
iface := network.DefaultInterface
|
||||
|
||||
client, err := wgctrl.New()
|
||||
if err != nil {
|
||||
return peers, err
|
||||
}
|
||||
device, err := client.Device(iface)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, peer := range device.Peers {
|
||||
if functions.IsBase64(peer.PublicKey.String()) && peer.Endpoint != nil && functions.CheckEndpoint(peer.Endpoint.String()) {
|
||||
peers[peer.PublicKey.String()] = peer.Endpoint.String()
|
||||
}
|
||||
}
|
||||
return peers, nil
|
||||
}
|
@@ -191,7 +191,7 @@ func TestAuthenticateUser(t *testing.T) {
|
||||
password: "xxxxxxx",
|
||||
code: http.StatusBadRequest,
|
||||
tokenExpected: false,
|
||||
errMessage: "Wrong Password",
|
||||
errMessage: "Incorrect Credentials",
|
||||
},
|
||||
AuthorizeTestCase{
|
||||
testname: "Valid User",
|
||||
|
Reference in New Issue
Block a user