mirror of
https://github.com/gravitl/netmaker.git
synced 2024-09-21 07:46:04 +08:00
commit
db4dcf4f54
11
.github/workflows/buildandrelease.yml
vendored
11
.github/workflows/buildandrelease.yml
vendored
|
@ -47,6 +47,7 @@ jobs:
|
|||
env CGO_ENABLED=0 GOOS=freebsd GOARCH=arm GOARM=7 go build -ldflags="-X 'main.version=${NETMAKER_VERSION}'" -o build/netclient-freebsd-arm7/netclient main.go
|
||||
env CGO_ENABLED=0 GOOS=freebsd GOARCH=arm64 go build -ldflags="-X 'main.version=${NETMAKER_VERSION}'" -o build/netclient-freebsd-arm64/netclient main.go
|
||||
env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags="-X 'main.version=${NETMAKER_VERSION}'" -o build/netclient-darwin/netclient main.go
|
||||
env CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags="-X 'main.version=${NETMAKER_VERSION}'" -o build/netclient-darwin-arm64/netclient main.go
|
||||
|
||||
- name: Upload netmaker x86 to Release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
|
@ -177,3 +178,13 @@ jobs:
|
|||
overwrite: true
|
||||
prerelease: true
|
||||
asset_name: netclient-darwin
|
||||
|
||||
- name: Upload darwin-arm64 to Release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: netclient/build/netclient-darwin-arm64/netclient
|
||||
tag: ${{ env.NETMAKER_VERSION }}
|
||||
overwrite: true
|
||||
prerelease: true
|
||||
asset_name: netclient-darwin-arm64
|
||||
|
|
57
.github/workflows/test-artifacts.yml
vendored
57
.github/workflows/test-artifacts.yml
vendored
|
@ -38,18 +38,51 @@ jobs:
|
|||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17
|
||||
- name: build client
|
||||
run: |
|
||||
cd netclient
|
||||
go build -ldflags="-X 'main.version=testing'" .
|
||||
curl -H 'Authorization: Bearer ${{ secrets.NUSAK_MASTERKEY }}' \
|
||||
-H 'Content-Type: multipart/form-data' --form upload='./netclient' \
|
||||
-X POST https://dashboard.nusak.ca/api/file/netclient
|
||||
#deploy:
|
||||
#runs-on: ubuntu-latest
|
||||
#steps:
|
||||
#- name: Deploy Testing Server and Client(s)
|
||||
# run: |
|
||||
# curl -X POST https://api.github.com/mattkasun/terraform-test/dispatches \
|
||||
# -H 'Accept: application/vnd.github.everest-preview+json' \
|
||||
# -u ${{ secrets.ACCESS_TOKEN }}
|
||||
go build -ldflags="-X 'main.version=testing'" -o build/netclient
|
||||
- name: deploy
|
||||
uses: mdallasanta/ssh-scp-deploy@v1.1.0
|
||||
with:
|
||||
local: ./netclient/build/netclient # Local file path - REQUIRED false - DEFAULT ./
|
||||
remote: /var/www/files/testing/ # Remote file path - REQUIRED false - DEFAULT ~/
|
||||
host: fileserver.clustercat.com # Remote server address - REQUIRED true
|
||||
#port: ${{secrets.PORT}} # Remote server port - REQUIRED false - DEFAULT 22
|
||||
user: root # Remote server user - REQUIRED true
|
||||
#password: ${{secrets.PASSWORD}} # User password - REQUIRED at least one of "password" or "key"
|
||||
key: ${{secrets.TESTING_SSH_KEY}} # Remote server private key - REQUIRED at least one of "password" or "key"
|
||||
#pre_upload: echo "This will be executed before the upload!" # Command to run via ssh before scp upload - REQUIRED false
|
||||
#post_upload: echo "This will be executed after the upload!" # Command to run via ssh after scp upload - REQUIRED false
|
||||
#ssh_options: -o StrictHostKeyChecking=no # A set of ssh_option separated by -o - REQUIRED false - DEFAULT -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null
|
||||
#scp_options: -v # Flags to use during scp - REQUIRED false - DEFAULT ''
|
||||
netmaker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17
|
||||
- name: build server
|
||||
run:
|
||||
go build -ldflags="-X 'main.version=testing'" -o build/netmaker
|
||||
- name: deploy
|
||||
uses: mdallasanta/ssh-scp-deploy@v1.1.0
|
||||
with:
|
||||
local: ./build/netmaker # Local file path - REQUIRED false - DEFAULT ./
|
||||
remote: /var/www/files/testing/ # Remote file path - REQUIRED false - DEFAULT ~/
|
||||
host: fileserver.clustercat.com # Remote server address - REQUIRED true
|
||||
#port: ${{secrets.PORT}} # Remote server port - REQUIRED false - DEFAULT 22
|
||||
user: root # Remote server user - REQUIRED true
|
||||
#password: ${{secrets.PASSWORD}} # User password - REQUIRED at least one of "password" or "key"
|
||||
key: ${{secrets.TESTING_SSH_KEY}} # Remote server private key - REQUIRED at least one of "password" or "key"
|
||||
#pre_upload: echo "This will be executed before the upload!" # Command to run via ssh before scp upload - REQUIRED false
|
||||
#post_upload: echo "This will be executed after the upload!" # Command to run via ssh after scp upload - REQUIRED false
|
||||
#ssh_options: -o StrictHostKeyChecking=no # A set of ssh_option separated by -o - REQUIRED false - DEFAULT -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null
|
||||
#scp_options: -v # Flags to use during scp - REQUIRED false - DEFAULT ''
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
<p align="center">
|
||||
<a href="https://github.com/gravitl/netmaker/releases">
|
||||
<img src="https://img.shields.io/badge/Version-0.10.0-informational?style=flat-square" />
|
||||
<img src="https://img.shields.io/badge/Version-0.11.0-informational?style=flat-square" />
|
||||
</a>
|
||||
<a href="https://hub.docker.com/r/gravitl/netmaker/tags">
|
||||
<img src="https://img.shields.io/docker/pulls/gravitl/netmaker" />
|
||||
|
|
|
@ -3,7 +3,7 @@ version: "3.4"
|
|||
services:
|
||||
netmaker:
|
||||
container_name: netmaker
|
||||
image: gravitl/netmaker:v0.10.0
|
||||
image: gravitl/netmaker:v0.11.0
|
||||
volumes:
|
||||
- dnsconfig:/root/config/dnsconfig
|
||||
- /usr/bin/wg:/usr/bin/wg
|
||||
|
@ -46,7 +46,7 @@ services:
|
|||
container_name: netmaker-ui
|
||||
depends_on:
|
||||
- netmaker
|
||||
image: gravitl/netmaker-ui:v0.10.0
|
||||
image: gravitl/netmaker-ui:v0.11.0
|
||||
links:
|
||||
- "netmaker:api"
|
||||
ports:
|
||||
|
|
|
@ -3,7 +3,7 @@ version: "3.4"
|
|||
services:
|
||||
netmaker:
|
||||
container_name: netmaker
|
||||
image: gravitl/netmaker:v0.10.0
|
||||
image: gravitl/netmaker:v0.11.0
|
||||
volumes:
|
||||
- dnsconfig:/root/config/dnsconfig
|
||||
- /usr/bin/wg:/usr/bin/wg
|
||||
|
@ -41,7 +41,7 @@ services:
|
|||
container_name: netmaker-ui
|
||||
depends_on:
|
||||
- netmaker
|
||||
image: gravitl/netmaker-ui:0.10.0
|
||||
image: gravitl/netmaker-ui:0.11.0
|
||||
links:
|
||||
- "netmaker:api"
|
||||
ports:
|
||||
|
@ -87,4 +87,4 @@ volumes:
|
|||
sqldata: {}
|
||||
dnsconfig: {}
|
||||
mosquitto_data: {}
|
||||
mosquitto_logs: {}
|
||||
mosquitto_logs: {}
|
||||
|
|
|
@ -3,7 +3,7 @@ version: "3.4"
|
|||
services:
|
||||
netmaker:
|
||||
container_name: netmaker
|
||||
image: gravitl/netmaker:v0.10.0
|
||||
image: gravitl/netmaker:v0.11.0
|
||||
volumes:
|
||||
- dnsconfig:/root/config/dnsconfig
|
||||
- /usr/bin/wg:/usr/bin/wg
|
||||
|
@ -46,7 +46,7 @@ services:
|
|||
container_name: netmaker-ui
|
||||
depends_on:
|
||||
- netmaker
|
||||
image: gravitl/netmaker-ui:v0.10.0
|
||||
image: gravitl/netmaker-ui:v0.11.0
|
||||
links:
|
||||
- "netmaker:api"
|
||||
ports:
|
||||
|
|
|
@ -3,7 +3,7 @@ version: "3.4"
|
|||
services:
|
||||
netmaker:
|
||||
container_name: netmaker
|
||||
image: gravitl/netmaker:v0.10.0
|
||||
image: gravitl/netmaker:v0.11.0
|
||||
volumes:
|
||||
- dnsconfig:/root/config/dnsconfig
|
||||
- /usr/bin/wg:/usr/bin/wg
|
||||
|
@ -46,7 +46,7 @@ services:
|
|||
container_name: netmaker-ui
|
||||
depends_on:
|
||||
- netmaker
|
||||
image: gravitl/netmaker-ui:v0.10.0
|
||||
image: gravitl/netmaker-ui:v0.11.0
|
||||
links:
|
||||
- "netmaker:api"
|
||||
ports:
|
||||
|
@ -79,4 +79,4 @@ volumes:
|
|||
caddy_conf: {}
|
||||
sqldata: {}
|
||||
mosquitto_data: {}
|
||||
mosquitto_logs: {}
|
||||
mosquitto_logs: {}
|
||||
|
|
|
@ -2,7 +2,7 @@ services:
|
|||
netmaker: # The Primary Server for running Netmaker
|
||||
privileged: true # Necessary to run sudo/root level commands on host system. Likely using this if running with host networking on.
|
||||
container_name: netmaker
|
||||
image: gravitl/netmaker:v0.10.0
|
||||
image: gravitl/netmaker:v0.11.0
|
||||
volumes: # Volume mounts necessary for CLIENT_MODE to control wireguard networking on host (except dnsconfig, which is where dns config files are stored for use by CoreDNS)
|
||||
- dnsconfig:/root/config/dnsconfig # Netmaker writes Corefile to this location, which gets mounted by CoreDNS for DNS configuration.
|
||||
- /usr/bin/wg:/usr/bin/wg
|
||||
|
@ -45,7 +45,7 @@ services:
|
|||
container_name: netmaker-ui
|
||||
depends_on:
|
||||
- netmaker
|
||||
image: gravitl/netmaker-ui:v0.10.0
|
||||
image: gravitl/netmaker-ui:v0.11.0
|
||||
links:
|
||||
- "netmaker:api"
|
||||
ports:
|
||||
|
@ -88,4 +88,4 @@ volumes:
|
|||
sqldata: {} # storage for embedded sqlite
|
||||
dnsconfig: {} # storage for coredns
|
||||
mosquitto_data: {} # storage for mqtt data
|
||||
mosquitto_logs: {} # storage for mqtt logs
|
||||
mosquitto_logs: {} # storage for mqtt logs
|
||||
|
|
|
@ -3,7 +3,7 @@ version: "3.4"
|
|||
services:
|
||||
netmaker:
|
||||
container_name: netmaker
|
||||
image: gravitl/netmaker:v0.10.0
|
||||
image: gravitl/netmaker:v0.11.0
|
||||
volumes:
|
||||
- dnsconfig:/root/config/dnsconfig
|
||||
- /usr/bin/wg:/usr/bin/wg
|
||||
|
@ -46,7 +46,7 @@ services:
|
|||
container_name: netmaker-ui
|
||||
depends_on:
|
||||
- netmaker
|
||||
image: gravitl/netmaker-ui:v0.10.0
|
||||
image: gravitl/netmaker-ui:v0.11.0
|
||||
links:
|
||||
- "netmaker:api"
|
||||
ports:
|
||||
|
|
|
@ -53,15 +53,12 @@ type ServerConfig struct {
|
|||
MessageQueueBackend string `yaml:"messagequeuebackend"`
|
||||
ClientMode string `yaml:"clientmode"`
|
||||
DNSMode string `yaml:"dnsmode"`
|
||||
SplitDNS string `yaml:"splitdns"`
|
||||
DisableRemoteIPCheck string `yaml:"disableremoteipcheck"`
|
||||
DisableDefaultNet string `yaml:"disabledefaultnet"`
|
||||
GRPCSSL string `yaml:"grpcssl"`
|
||||
Version string `yaml:"version"`
|
||||
SQLConn string `yaml:"sqlconn"`
|
||||
Platform string `yaml:"platform"`
|
||||
Database string `yaml:"database"`
|
||||
CheckinInterval string `yaml:"checkininterval"`
|
||||
DefaultNodeLimit int32 `yaml:"defaultnodelimit"`
|
||||
Verbosity int32 `yaml:"verbosity"`
|
||||
ServerCheckinInterval int64 `yaml:"servercheckininterval"`
|
||||
|
@ -77,6 +74,9 @@ type ServerConfig struct {
|
|||
ManageIPTables string `yaml:"manageiptables"`
|
||||
PortForwardServices string `yaml:"portforwardservices"`
|
||||
HostNetwork string `yaml:"hostnetwork"`
|
||||
CommsCIDR string `yaml:"commscidr"`
|
||||
MQPort string `yaml:"mqport"`
|
||||
CommsID string `yaml:"commsid"`
|
||||
}
|
||||
|
||||
// SQLConfig - Generic SQL Config
|
||||
|
|
|
@ -125,7 +125,7 @@ func getExtClientConf(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
gwnode, err := logic.GetNodeByID(client.IngressGatewayID)
|
||||
if err != nil {
|
||||
logger.Log(1, fmt.Sprintf("%s %s %s", r.Header.Get("user"), "Could not retrieve Ingress Gateway Node", client.IngressGatewayID))
|
||||
logger.Log(1, r.Header.Get("user"), "Could not retrieve Ingress Gateway Node", client.IngressGatewayID)
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
|
|
|
@ -14,9 +14,13 @@ import (
|
|||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/mq"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"github.com/gravitl/netmaker/serverctl"
|
||||
)
|
||||
|
||||
// ALL_NETWORK_ACCESS - represents all networks
|
||||
const ALL_NETWORK_ACCESS = "THIS_USER_HAS_ALL"
|
||||
|
||||
// NO_NETWORKS_PRESENT - represents no networks
|
||||
const NO_NETWORKS_PRESENT = "THIS_USER_HAS_NONE"
|
||||
|
||||
func networkHandlers(r *mux.Router) {
|
||||
|
@ -26,7 +30,7 @@ func networkHandlers(r *mux.Router) {
|
|||
r.HandleFunc("/api/networks/{networkname}", securityCheck(false, http.HandlerFunc(updateNetwork))).Methods("PUT")
|
||||
r.HandleFunc("/api/networks/{networkname}/nodelimit", securityCheck(true, http.HandlerFunc(updateNetworkNodeLimit))).Methods("PUT")
|
||||
r.HandleFunc("/api/networks/{networkname}", securityCheck(true, http.HandlerFunc(deleteNetwork))).Methods("DELETE")
|
||||
r.HandleFunc("/api/networks/{networkname}/keyupdate", securityCheck(false, http.HandlerFunc(keyUpdate))).Methods("POST")
|
||||
r.HandleFunc("/api/networks/{networkname}/keyupdate", securityCheck(true, http.HandlerFunc(keyUpdate))).Methods("POST")
|
||||
r.HandleFunc("/api/networks/{networkname}/keys", securityCheck(false, http.HandlerFunc(createAccessKey))).Methods("POST")
|
||||
r.HandleFunc("/api/networks/{networkname}/keys", securityCheck(false, http.HandlerFunc(getAccessKeys))).Methods("GET")
|
||||
r.HandleFunc("/api/networks/{networkname}/keys/{name}", securityCheck(false, http.HandlerFunc(deleteAccessKey))).Methods("DELETE")
|
||||
|
@ -43,7 +47,7 @@ func getNetworks(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
allnetworks := []models.Network{}
|
||||
err := errors.New("Networks Error")
|
||||
var err error
|
||||
if networksSlice[0] == ALL_NETWORK_ACCESS {
|
||||
allnetworks, err = logic.GetNetworks()
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
|
@ -64,6 +68,7 @@ func getNetworks(w http.ResponseWriter, r *http.Request) {
|
|||
allnetworks[i] = net
|
||||
}
|
||||
}
|
||||
|
||||
logger.Log(2, r.Header.Get("user"), "fetched networks.")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(allnetworks)
|
||||
|
@ -75,6 +80,10 @@ func getNetwork(w http.ResponseWriter, r *http.Request) {
|
|||
w.Header().Set("Content-Type", "application/json")
|
||||
var params = mux.Vars(r)
|
||||
netname := params["networkname"]
|
||||
if isCommsEdit(w, r, netname) {
|
||||
return
|
||||
}
|
||||
|
||||
network, err := logic.GetNetwork(netname)
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
|
@ -92,6 +101,10 @@ func keyUpdate(w http.ResponseWriter, r *http.Request) {
|
|||
w.Header().Set("Content-Type", "application/json")
|
||||
var params = mux.Vars(r)
|
||||
netname := params["networkname"]
|
||||
if isCommsEdit(w, r, netname) {
|
||||
return
|
||||
}
|
||||
|
||||
network, err := logic.KeyUpdate(netname)
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
|
@ -106,17 +119,13 @@ func keyUpdate(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
for _, node := range nodes {
|
||||
fmt.Println("updating node ", node.Name, " for a key update")
|
||||
if err := mq.NodeUpdate(&node); err != nil {
|
||||
logger.Log(2, "failed key update ", node.Name)
|
||||
logger.Log(2, "updating node ", node.Name, " for a key update")
|
||||
if node.IsServer != "yes" {
|
||||
if err = mq.NodeUpdate(&node); err != nil {
|
||||
logger.Log(1, "failed to send update to node during a network wide key update", node.Name, node.ID, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
node, err := logic.GetNetworkServerLeader(netname)
|
||||
if err != nil {
|
||||
logger.Log(2, "failed to get server node")
|
||||
return
|
||||
}
|
||||
runUpdates(&node, false)
|
||||
}
|
||||
|
||||
// Update a network
|
||||
|
@ -125,6 +134,10 @@ func updateNetwork(w http.ResponseWriter, r *http.Request) {
|
|||
var params = mux.Vars(r)
|
||||
var network models.Network
|
||||
netname := params["networkname"]
|
||||
if isCommsEdit(w, r, netname) {
|
||||
return
|
||||
}
|
||||
|
||||
network, err := logic.GetParentNetwork(netname)
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
|
@ -181,7 +194,9 @@ func updateNetwork(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
for _, node := range nodes {
|
||||
runUpdates(&node, true)
|
||||
if err = mq.NodeUpdate(&node); err != nil {
|
||||
logger.Log(1, "failed to send update to node during a network wide update", node.Name, node.ID, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -227,8 +242,11 @@ func deleteNetwork(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
var params = mux.Vars(r)
|
||||
network := params["networkname"]
|
||||
err := logic.DeleteNetwork(network)
|
||||
if isCommsEdit(w, r, network) {
|
||||
return
|
||||
}
|
||||
|
||||
err := logic.DeleteNetwork(network)
|
||||
if err != nil {
|
||||
errtype := "badrequest"
|
||||
if strings.Contains(err.Error(), "Node check failed") {
|
||||
|
@ -267,7 +285,7 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
|
|||
if err != nil {
|
||||
logic.DeleteNetwork(network.NetID)
|
||||
if err == nil {
|
||||
err = errors.New("Failed to add server to network " + network.DisplayName)
|
||||
err = errors.New("Failed to add server to network " + network.NetID)
|
||||
}
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
|
@ -286,6 +304,9 @@ func createAccessKey(w http.ResponseWriter, r *http.Request) {
|
|||
var accesskey models.AccessKey
|
||||
//start here
|
||||
netname := params["networkname"]
|
||||
if isCommsEdit(w, r, netname) {
|
||||
return
|
||||
}
|
||||
network, err := logic.GetParentNetwork(netname)
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
|
@ -338,3 +359,21 @@ func deleteAccessKey(w http.ResponseWriter, r *http.Request) {
|
|||
logger.Log(1, r.Header.Get("user"), "deleted access key", keyname, "on network,", netname)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func isCommsEdit(w http.ResponseWriter, r *http.Request, netname string) bool {
|
||||
if netname == serverctl.COMMS_NETID {
|
||||
returnErrorResponse(w, r, formatError(fmt.Errorf("cannot access comms network"), "internal"))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func filterCommsNetwork(networks []models.Network) []models.Network {
|
||||
var filterdNets []models.Network
|
||||
for i := range networks {
|
||||
if networks[i].IsComms != "yes" && networks[i].NetID != servercfg.GetCommsID() {
|
||||
filterdNets = append(filterdNets, networks[i])
|
||||
}
|
||||
}
|
||||
return filterdNets
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
package controller
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/serverctl"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
@ -23,7 +24,8 @@ func TestCreateNetwork(t *testing.T) {
|
|||
var network models.Network
|
||||
network.NetID = "skynet"
|
||||
network.AddressRange = "10.0.0.1/24"
|
||||
network.DisplayName = "mynetwork"
|
||||
// if tests break - check here (removed displayname)
|
||||
//network.DisplayName = "mynetwork"
|
||||
|
||||
err := logic.CreateNetwork(network)
|
||||
assert.Nil(t, err)
|
||||
|
@ -60,20 +62,6 @@ func TestDeleteNetwork(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestKeyUpdate(t *testing.T) {
|
||||
t.Skip() //test is failing on last assert --- not sure why
|
||||
database.InitializeDatabase()
|
||||
createNet()
|
||||
existing, err := logic.GetNetwork("skynet")
|
||||
assert.Nil(t, err)
|
||||
time.Sleep(time.Second * 1)
|
||||
network, err := logic.KeyUpdate("skynet")
|
||||
assert.Nil(t, err)
|
||||
network, err = logic.GetNetwork("skynet")
|
||||
assert.Nil(t, err)
|
||||
assert.Greater(t, network.KeyUpdateTimeStamp, existing.KeyUpdateTimeStamp)
|
||||
}
|
||||
|
||||
func TestCreateKey(t *testing.T) {
|
||||
database.InitializeDatabase()
|
||||
createNet()
|
||||
|
@ -193,6 +181,7 @@ func TestSecurityCheck(t *testing.T) {
|
|||
//these seem to work but not sure it the tests are really testing the functionality
|
||||
|
||||
database.InitializeDatabase()
|
||||
os.Setenv("MASTER_KEY", "secretkey")
|
||||
t.Run("NoNetwork", func(t *testing.T) {
|
||||
err, networks, username := SecurityCheck(false, "", "Bearer secretkey")
|
||||
assert.Nil(t, err)
|
||||
|
@ -243,28 +232,6 @@ func TestValidateNetworkUpdate(t *testing.T) {
|
|||
},
|
||||
errMessage: "Field validation for 'AddressRange6' failed on the 'cidr' tag",
|
||||
},
|
||||
|
||||
{
|
||||
testname: "BadDisplayName",
|
||||
network: models.Network{
|
||||
DisplayName: "skynet*",
|
||||
},
|
||||
errMessage: "Field validation for 'DisplayName' failed on the 'alphanum' tag",
|
||||
},
|
||||
{
|
||||
testname: "DisplayNameTooLong",
|
||||
network: models.Network{
|
||||
DisplayName: "Thisisareallylongdisplaynamethatistoolong",
|
||||
},
|
||||
errMessage: "Field validation for 'DisplayName' failed on the 'max' tag",
|
||||
},
|
||||
{
|
||||
testname: "DisplayNameTooShort",
|
||||
network: models.Network{
|
||||
DisplayName: "1",
|
||||
},
|
||||
errMessage: "Field validation for 'DisplayName' failed on the 'min' tag",
|
||||
},
|
||||
{
|
||||
testname: "InvalidNetID",
|
||||
network: models.Network{
|
||||
|
@ -307,20 +274,6 @@ func TestValidateNetworkUpdate(t *testing.T) {
|
|||
},
|
||||
errMessage: "Field validation for 'LocalRange' failed on the 'cidr' tag",
|
||||
},
|
||||
{
|
||||
testname: "CheckInIntervalTooBig",
|
||||
network: models.Network{
|
||||
DefaultCheckInInterval: 100001,
|
||||
},
|
||||
errMessage: "Field validation for 'DefaultCheckInInterval' failed on the 'max' tag",
|
||||
},
|
||||
{
|
||||
testname: "CheckInIntervalTooSmall",
|
||||
network: models.Network{
|
||||
DefaultCheckInInterval: 1,
|
||||
},
|
||||
errMessage: "Field validation for 'DefaultCheckInInterval' failed on the 'min' tag",
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.testname, func(t *testing.T) {
|
||||
|
@ -344,9 +297,9 @@ func createNet() {
|
|||
var network models.Network
|
||||
network.NetID = "skynet"
|
||||
network.AddressRange = "10.0.0.1/24"
|
||||
network.DisplayName = "mynetwork"
|
||||
_, err := logic.GetNetwork("skynet")
|
||||
if err != nil {
|
||||
logic.CreateNetwork(network)
|
||||
}
|
||||
serverctl.InitializeCommsNetwork()
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
|
@ -182,6 +181,13 @@ func authorize(networkCheck bool, authNetwork string, next http.Handler) http.Ha
|
|||
var isAuthorized = false
|
||||
var nodeID = ""
|
||||
username, networks, isadmin, errN := logic.VerifyUserToken(authToken)
|
||||
if errN != nil {
|
||||
errorResponse = models.ErrorResponse{
|
||||
Code: http.StatusUnauthorized, Message: "W1R3: Unauthorized, Invalid Token Processed.",
|
||||
}
|
||||
returnErrorResponse(w, r, errorResponse)
|
||||
return
|
||||
}
|
||||
isnetadmin := isadmin
|
||||
if errN == nil && isadmin {
|
||||
nodeID = "mastermac"
|
||||
|
@ -257,6 +263,7 @@ func getNetworkNodes(w http.ResponseWriter, r *http.Request) {
|
|||
var nodes []models.Node
|
||||
var params = mux.Vars(r)
|
||||
networkName := params["network"]
|
||||
|
||||
nodes, err := logic.GetNetworkNodes(networkName)
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
|
@ -293,9 +300,9 @@ func getAllNodes(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
//Return all the nodes in JSON format
|
||||
logger.Log(2, r.Header.Get("user"), "fetched nodes")
|
||||
logger.Log(3, r.Header.Get("user"), "fetched all nodes they have access to")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(nodes)
|
||||
json.NewEncoder(w).Encode(filterCommsNodes(nodes))
|
||||
}
|
||||
|
||||
func getUsersNodes(user models.User) ([]models.Node, error) {
|
||||
|
@ -323,6 +330,10 @@ func getNode(w http.ResponseWriter, r *http.Request) {
|
|||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
if logic.IsNodeInComms(&node) {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
logger.Log(2, r.Header.Get("user"), "fetched node", params["nodeid"])
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(node)
|
||||
|
@ -389,8 +400,8 @@ func createNode(w http.ResponseWriter, r *http.Request) {
|
|||
validKey := logic.IsKeyValid(networkName, node.AccessKey)
|
||||
|
||||
if !validKey {
|
||||
//Check to see if network will allow manual sign up
|
||||
//may want to switch this up with the valid key check and avoid a DB call that way.
|
||||
// Check to see if network will allow manual sign up
|
||||
// may want to switch this up with the valid key check and avoid a DB call that way.
|
||||
if network.AllowManualSignUp == "yes" {
|
||||
node.IsPending = "yes"
|
||||
} else {
|
||||
|
@ -411,12 +422,11 @@ func createNode(w http.ResponseWriter, r *http.Request) {
|
|||
logger.Log(1, r.Header.Get("user"), "created new node", node.Name, "on network", node.Network)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(node)
|
||||
|
||||
runUpdates(&node, false)
|
||||
runForceServerUpdate(&node)
|
||||
}
|
||||
|
||||
//Takes node out of pending state
|
||||
//TODO: May want to use cordon/uncordon terminology instead of "ispending".
|
||||
// Takes node out of pending state
|
||||
// TODO: May want to use cordon/uncordon terminology instead of "ispending".
|
||||
func uncordonNode(w http.ResponseWriter, r *http.Request) {
|
||||
var params = mux.Vars(r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
@ -430,9 +440,11 @@ func uncordonNode(w http.ResponseWriter, r *http.Request) {
|
|||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode("SUCCESS")
|
||||
|
||||
runUpdates(&node, true)
|
||||
runUpdates(&node, false)
|
||||
}
|
||||
|
||||
// == EGRESS ==
|
||||
|
||||
func createEgressGateway(w http.ResponseWriter, r *http.Request) {
|
||||
var gateway models.EgressGatewayRequest
|
||||
var params = mux.Vars(r)
|
||||
|
@ -532,7 +544,6 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
|
|||
returnErrorResponse(w, r, formatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
newNode.PullChanges = "yes"
|
||||
relayupdate := false
|
||||
if node.IsRelay == "yes" && len(newNode.RelayAddrs) > 0 {
|
||||
if len(newNode.RelayAddrs) != len(node.RelayAddrs) {
|
||||
|
@ -551,6 +562,8 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
|
|||
newNode.PostUp = node.PostUp
|
||||
}
|
||||
|
||||
ifaceDelta := logic.IfaceDelta(&node, &newNode)
|
||||
|
||||
err = logic.UpdateNode(&node, &newNode)
|
||||
if err != nil {
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
|
@ -563,10 +576,7 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
if len(updatenodes) > 0 {
|
||||
for _, relayedNode := range updatenodes {
|
||||
err = mq.NodeUpdate(&relayedNode)
|
||||
if err != nil {
|
||||
logger.Log(1, "error sending update to relayed node ", relayedNode.Address, "on network", node.Network, ": ", err.Error())
|
||||
}
|
||||
runUpdates(&relayedNode, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -579,7 +589,7 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
|
|||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(newNode)
|
||||
|
||||
runUpdates(&newNode, true)
|
||||
runUpdates(&newNode, ifaceDelta)
|
||||
}
|
||||
|
||||
func deleteNode(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -600,11 +610,6 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
//send update to node to be deleted before deleting on server otherwise message cannot be sent
|
||||
node.Action = models.NODE_DELETE
|
||||
if err := mq.NodeUpdate(&node); err != nil {
|
||||
logger.Log(1, "error publishing node update", err.Error())
|
||||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
|
||||
err = logic.DeleteNodeByID(&node, false)
|
||||
if err != nil {
|
||||
|
@ -613,25 +618,59 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
returnSuccessResponse(w, r, nodeid+" deleted.")
|
||||
|
||||
time.Sleep(time.Second << 1)
|
||||
logger.Log(1, r.Header.Get("user"), "Deleted node", nodeid, "from network", params["network"])
|
||||
runUpdates(&node, false)
|
||||
runForceServerUpdate(&node)
|
||||
}
|
||||
|
||||
func runUpdates(node *models.Node, nodeUpdate bool) error {
|
||||
//don't publish to server node
|
||||
|
||||
if nodeUpdate && !isServer(node) {
|
||||
if err := mq.NodeUpdate(node); err != nil {
|
||||
logger.Log(1, "error publishing node update", err.Error())
|
||||
return err
|
||||
func runUpdates(node *models.Node, ifaceDelta bool) {
|
||||
go func() { // don't block http response
|
||||
err := logic.TimerCheckpoint()
|
||||
if err != nil {
|
||||
logger.Log(3, "error occurred on timer,", err.Error())
|
||||
}
|
||||
// publish node update if not server
|
||||
if err := mq.NodeUpdate(node); err != nil {
|
||||
logger.Log(1, "error publishing node update to node", node.Name, node.ID, err.Error())
|
||||
}
|
||||
|
||||
if err := runServerUpdate(node, ifaceDelta); err != nil {
|
||||
logger.Log(1, "error running server update", err.Error())
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// updates local peers for a server on a given node's network
|
||||
func runServerUpdate(node *models.Node, ifaceDelta bool) error {
|
||||
|
||||
if servercfg.IsClientMode() != "on" || !isServer(node) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := runServerPeerUpdate(node, isServer(node)); err != nil {
|
||||
logger.Log(1, "internal error when running peer node:", err.Error())
|
||||
currentServerNode, err := logic.GetNetworkServerLocal(node.Network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ifaceDelta && logic.IsLeader(¤tServerNode) {
|
||||
if err := mq.PublishPeerUpdate(¤tServerNode); err != nil {
|
||||
logger.Log(1, "failed to publish peer update "+err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if err := logic.ServerUpdate(¤tServerNode, ifaceDelta); err != nil {
|
||||
logger.Log(1, "server node:", currentServerNode.ID, "failed update")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func filterCommsNodes(nodes []models.Node) []models.Node {
|
||||
var filterdNodes []models.Node
|
||||
for i := range nodes {
|
||||
if !logic.IsNodeInComms(&nodes[i]) {
|
||||
filterdNodes = append(filterdNodes, nodes[i])
|
||||
}
|
||||
}
|
||||
return filterdNodes
|
||||
}
|
||||
|
|
|
@ -92,6 +92,12 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.Object)
|
|||
Server: key,
|
||||
}
|
||||
|
||||
commID, err := logic.FetchCommsNetID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
node.CommID = commID
|
||||
|
||||
err = logic.CreateNode(&node)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -107,7 +113,7 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.Object)
|
|||
Type: nodepb.NODE_TYPE,
|
||||
}
|
||||
|
||||
runUpdates(&node, false)
|
||||
runForceServerUpdate(&node)
|
||||
|
||||
go func(node *models.Node) {
|
||||
if node.UDPHolePunch == "yes" {
|
||||
|
@ -134,6 +140,7 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.Object)
|
|||
}
|
||||
|
||||
// NodeServiceServer.UpdateNode updates a node and responds over gRPC
|
||||
// DELETE ONE DAY - DEPRECATED
|
||||
func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
|
||||
|
||||
var newnode models.Node
|
||||
|
@ -166,8 +173,6 @@ func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.Object)
|
|||
return nil, err
|
||||
}
|
||||
|
||||
runUpdates(&newnode, false)
|
||||
|
||||
return &nodepb.Object{
|
||||
Data: string(nodeData),
|
||||
Type: nodepb.NODE_TYPE,
|
||||
|
@ -175,10 +180,10 @@ func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.Object)
|
|||
}
|
||||
|
||||
func getServerAddrs(node *models.Node) {
|
||||
serverNodes := logic.GetServerNodes(node.Network)
|
||||
serverNodes := logic.GetServerNodes(serverctl.COMMS_NETID)
|
||||
//pubIP, _ := servercfg.GetPublicIP()
|
||||
if len(serverNodes) == 0 {
|
||||
if err := serverctl.SyncServerNetwork(node.Network); err != nil {
|
||||
if err := serverctl.SyncServerNetwork(serverctl.COMMS_NETID); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -217,7 +222,7 @@ func (s *NodeServiceServer) DeleteNode(ctx context.Context, req *nodepb.Object)
|
|||
return nil, err
|
||||
}
|
||||
|
||||
runServerPeerUpdate(&node, false)
|
||||
runForceServerUpdate(&node)
|
||||
|
||||
return &nodepb.Object{
|
||||
Data: "success",
|
||||
|
@ -233,12 +238,7 @@ func (s *NodeServiceServer) GetPeers(ctx context.Context, req *nodepb.Object) (*
|
|||
return nil, err
|
||||
}
|
||||
|
||||
excludeIsRelayed := node.IsRelay != "yes"
|
||||
var relayedNode string
|
||||
if node.IsRelayed == "yes" {
|
||||
relayedNode = node.Address
|
||||
}
|
||||
peers, err := logic.GetPeersList(node.Network, excludeIsRelayed, relayedNode)
|
||||
peers, err := logic.GetPeersList(&node)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), logic.RELAY_NODE_ERR) {
|
||||
peers, err = logic.PeerListUnRelay(node.ID, node.Network)
|
||||
|
@ -309,3 +309,18 @@ func getNodeFromRequestData(data string) (models.Node, error) {
|
|||
func isServer(node *models.Node) bool {
|
||||
return node.IsServer == "yes"
|
||||
}
|
||||
|
||||
func runForceServerUpdate(node *models.Node) {
|
||||
go func() {
|
||||
if err := mq.PublishPeerUpdate(node); err != nil {
|
||||
logger.Log(1, "failed a peer update after creation of node", node.Name)
|
||||
}
|
||||
|
||||
var currentServerNode, getErr = logic.GetNetworkServerLeader(node.Network)
|
||||
if getErr == nil {
|
||||
if err := logic.ServerUpdate(¤tServerNode, false); err != nil {
|
||||
logger.Log(1, "server node:", currentServerNode.ID, "failed update")
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
|
|
@ -98,9 +98,9 @@ func SecurityCheck(reqAdmin bool, netname string, token string) (error, []string
|
|||
return nil, userNetworks, username
|
||||
}
|
||||
|
||||
//Consider a more secure way of setting master key
|
||||
// Consider a more secure way of setting master key
|
||||
func authenticateMaster(tokenString string) bool {
|
||||
return tokenString == servercfg.GetMasterKey()
|
||||
return tokenString == servercfg.GetMasterKey() && servercfg.GetMasterKey() != ""
|
||||
}
|
||||
|
||||
//Consider a more secure way of setting master key
|
||||
|
|
|
@ -49,7 +49,7 @@ func securityCheckServer(adminonly bool, next http.Handler) http.HandlerFunc {
|
|||
returnErrorResponse(w, r, errorResponse)
|
||||
return
|
||||
}
|
||||
if adminonly && !isadmin && !authenticateMasterServer(authToken) {
|
||||
if adminonly && !isadmin && !authenticateMaster(authToken) {
|
||||
returnErrorResponse(w, r, errorResponse)
|
||||
return
|
||||
}
|
||||
|
@ -57,11 +57,6 @@ func securityCheckServer(adminonly bool, next http.Handler) http.HandlerFunc {
|
|||
}
|
||||
}
|
||||
|
||||
//Consider a more secure way of setting master key
|
||||
func authenticateMasterServer(tokenString string) bool {
|
||||
return tokenString == servercfg.GetMasterKey()
|
||||
}
|
||||
|
||||
func removeNetwork(w http.ResponseWriter, r *http.Request) {
|
||||
// Set header
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
package controller
|
||||
|
||||
import (
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/mq"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
)
|
||||
|
||||
func runServerPeerUpdate(node *models.Node, ifaceDelta bool) error {
|
||||
|
||||
err := logic.TimerCheckpoint()
|
||||
if err != nil {
|
||||
logger.Log(3, "error occurred on timer,", err.Error())
|
||||
}
|
||||
|
||||
if err := mq.PublishPeerUpdate(node); err != nil {
|
||||
logger.Log(0, "failed to inform peers of new node ", err.Error())
|
||||
}
|
||||
|
||||
if servercfg.IsClientMode() != "on" {
|
||||
return nil
|
||||
}
|
||||
var currentServerNode, getErr = logic.GetNetworkServerLeader(node.Network)
|
||||
if err != nil {
|
||||
return getErr
|
||||
}
|
||||
if err = logic.ServerUpdate(¤tServerNode, ifaceDelta); err != nil {
|
||||
logger.Log(1, "server node:", currentServerNode.ID, "failed update")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
)
|
||||
|
||||
func userHandlers(r *mux.Router) {
|
||||
|
@ -166,6 +167,11 @@ func createUser(w http.ResponseWriter, r *http.Request) {
|
|||
// get node from body of request
|
||||
_ = json.NewDecoder(r.Body).Decode(&user)
|
||||
|
||||
if !user.IsAdmin && isAddingComms(user.Networks) {
|
||||
returnErrorResponse(w, r, formatError(fmt.Errorf("can not add comms network to non admin"), "badrequest"))
|
||||
return
|
||||
}
|
||||
|
||||
user, err := logic.CreateUser(user)
|
||||
|
||||
if err != nil {
|
||||
|
@ -194,6 +200,10 @@ func updateUserNetworks(w http.ResponseWriter, r *http.Request) {
|
|||
returnErrorResponse(w, r, formatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
if !userchange.IsAdmin && isAddingComms(userchange.Networks) {
|
||||
returnErrorResponse(w, r, formatError(fmt.Errorf("can not add comms network to non admin"), "badrequest"))
|
||||
return
|
||||
}
|
||||
|
||||
err = logic.UpdateUserNetworks(userchange.Networks, userchange.IsAdmin, &user)
|
||||
if err != nil {
|
||||
|
@ -219,6 +229,10 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
|
|||
returnErrorResponse(w, r, formatError(fmt.Errorf("can not update user info for oauth user %s", username), "forbidden"))
|
||||
return
|
||||
}
|
||||
if !user.IsAdmin && isAddingComms(user.Networks) {
|
||||
returnErrorResponse(w, r, formatError(fmt.Errorf("can not add comms network to non admin"), "badrequest"))
|
||||
return
|
||||
}
|
||||
var userchange models.User
|
||||
// we decode our body request params
|
||||
err = json.NewDecoder(r.Body).Decode(&userchange)
|
||||
|
@ -288,3 +302,13 @@ func deleteUser(w http.ResponseWriter, r *http.Request) {
|
|||
logger.Log(1, username, "was deleted")
|
||||
json.NewEncoder(w).Encode(params["username"] + " deleted.")
|
||||
}
|
||||
|
||||
func isAddingComms(networks []string) bool {
|
||||
commsID := servercfg.GetCommsID()
|
||||
for i := range networks {
|
||||
if networks[i] == commsID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -32,9 +32,6 @@ const DNS_TABLE_NAME = "dns"
|
|||
// EXT_CLIENT_TABLE_NAME - ext client table
|
||||
const EXT_CLIENT_TABLE_NAME = "extclients"
|
||||
|
||||
// INT_CLIENTS_TABLE_NAME - int client table
|
||||
const INT_CLIENTS_TABLE_NAME = "intclients"
|
||||
|
||||
// PEERS_TABLE_NAME - peers table
|
||||
const PEERS_TABLE_NAME = "peers"
|
||||
|
||||
|
@ -126,7 +123,6 @@ func createTables() {
|
|||
createTable(USERS_TABLE_NAME)
|
||||
createTable(DNS_TABLE_NAME)
|
||||
createTable(EXT_CLIENT_TABLE_NAME)
|
||||
createTable(INT_CLIENTS_TABLE_NAME)
|
||||
createTable(PEERS_TABLE_NAME)
|
||||
createTable(SERVERCONF_TABLE_NAME)
|
||||
createTable(SERVER_UUID_TABLE_NAME)
|
||||
|
|
|
@ -2,100 +2,12 @@ package functions
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
)
|
||||
|
||||
// ParseNode - parses a node into a model
|
||||
func ParseNode(value string) (models.Node, error) {
|
||||
var node models.Node
|
||||
err := json.Unmarshal([]byte(value), &node)
|
||||
return node, err
|
||||
}
|
||||
|
||||
// ParseExtClient - parses an extclient into a model
|
||||
func ParseExtClient(value string) (models.ExtClient, error) {
|
||||
var extClient models.ExtClient
|
||||
err := json.Unmarshal([]byte(value), &extClient)
|
||||
return extClient, err
|
||||
}
|
||||
|
||||
// ParseIntClient - parses int client
|
||||
func ParseIntClient(value string) (models.IntClient, error) {
|
||||
var intClient models.IntClient
|
||||
err := json.Unmarshal([]byte(value), &intClient)
|
||||
return intClient, err
|
||||
}
|
||||
|
||||
// GetPeersList - gets peers for given network
|
||||
func GetPeersList(networkName string) ([]models.PeersResponse, error) {
|
||||
|
||||
var peers []models.PeersResponse
|
||||
collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
|
||||
if err != nil {
|
||||
return peers, err
|
||||
}
|
||||
|
||||
for _, value := range collection {
|
||||
|
||||
var peer models.PeersResponse
|
||||
err := json.Unmarshal([]byte(value), &peer)
|
||||
if err != nil {
|
||||
continue // try the rest
|
||||
}
|
||||
peers = append(peers, peer)
|
||||
}
|
||||
|
||||
return peers, err
|
||||
}
|
||||
|
||||
// GetIntPeersList - get int peers list
|
||||
func GetIntPeersList() ([]models.PeersResponse, error) {
|
||||
|
||||
var peers []models.PeersResponse
|
||||
records, err := database.FetchRecords(database.INT_CLIENTS_TABLE_NAME)
|
||||
|
||||
if err != nil {
|
||||
return peers, err
|
||||
}
|
||||
// parse the peers
|
||||
|
||||
for _, value := range records {
|
||||
|
||||
var peer models.PeersResponse
|
||||
err := json.Unmarshal([]byte(value), &peer)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// add the node to our node array
|
||||
//maybe better to just return this? But then that's just GetNodes...
|
||||
peers = append(peers, peer)
|
||||
}
|
||||
|
||||
return peers, err
|
||||
}
|
||||
|
||||
// GetServerIntClient - get server int client
|
||||
func GetServerIntClient() (*models.IntClient, error) {
|
||||
|
||||
intClients, err := database.FetchRecords(database.INT_CLIENTS_TABLE_NAME)
|
||||
for _, value := range intClients {
|
||||
var intClient models.IntClient
|
||||
err = json.Unmarshal([]byte(value), &intClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if intClient.IsServer == "yes" && intClient.Network == "comms" {
|
||||
return &intClient, nil
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// NetworkExists - check if network exists
|
||||
func NetworkExists(name string) (bool, error) {
|
||||
|
||||
|
@ -107,54 +19,6 @@ func NetworkExists(name string) (bool, error) {
|
|||
return len(network) > 0, nil
|
||||
}
|
||||
|
||||
// IsNetworkDisplayNameUnique - checks if network display name unique
|
||||
func IsNetworkDisplayNameUnique(name string) (bool, error) {
|
||||
|
||||
isunique := true
|
||||
|
||||
dbs, err := logic.GetNetworks()
|
||||
if err != nil {
|
||||
return database.IsEmptyRecord(err), err
|
||||
}
|
||||
|
||||
for i := 0; i < len(dbs); i++ {
|
||||
|
||||
if name == dbs[i].DisplayName {
|
||||
isunique = false
|
||||
}
|
||||
}
|
||||
|
||||
return isunique, nil
|
||||
}
|
||||
|
||||
// IsKeyValidGlobal - checks if a key is valid globally
|
||||
func IsKeyValidGlobal(keyvalue string) bool {
|
||||
|
||||
networks, _ := logic.GetNetworks()
|
||||
var key models.AccessKey
|
||||
foundkey := false
|
||||
isvalid := false
|
||||
for _, network := range networks {
|
||||
for i := len(network.AccessKeys) - 1; i >= 0; i-- {
|
||||
currentkey := network.AccessKeys[i]
|
||||
if currentkey.Value == keyvalue {
|
||||
key = currentkey
|
||||
foundkey = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if foundkey {
|
||||
break
|
||||
}
|
||||
}
|
||||
if foundkey {
|
||||
if key.Uses > 0 {
|
||||
isvalid = true
|
||||
}
|
||||
}
|
||||
return isvalid
|
||||
}
|
||||
|
||||
// NameInDNSCharSet - name in dns char set
|
||||
func NameInDNSCharSet(name string) bool {
|
||||
|
||||
|
@ -186,37 +50,6 @@ func RemoveDeletedNode(nodeid string) bool {
|
|||
return database.DeleteRecord(database.DELETED_NODES_TABLE_NAME, nodeid) == nil
|
||||
}
|
||||
|
||||
// DeleteAllIntClients - delete all int clients
|
||||
func DeleteAllIntClients() error {
|
||||
err := database.DeleteAllRecords(database.INT_CLIENTS_TABLE_NAME)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAllIntClients - get all int clients
|
||||
func GetAllIntClients() ([]models.IntClient, error) {
|
||||
var clients []models.IntClient
|
||||
collection, err := database.FetchRecords(database.INT_CLIENTS_TABLE_NAME)
|
||||
|
||||
if err != nil {
|
||||
return clients, err
|
||||
}
|
||||
|
||||
for _, value := range collection {
|
||||
var client models.IntClient
|
||||
err := json.Unmarshal([]byte(value), &client)
|
||||
if err != nil {
|
||||
return []models.IntClient{}, err
|
||||
}
|
||||
// add node to our array
|
||||
clients = append(clients, client)
|
||||
}
|
||||
|
||||
return clients, nil
|
||||
}
|
||||
|
||||
// GetAllExtClients - get all ext clients
|
||||
func GetAllExtClients() ([]models.ExtClient, error) {
|
||||
var extclients []models.ExtClient
|
||||
|
|
7
go.mod
7
go.mod
|
@ -5,7 +5,7 @@ go 1.17
|
|||
require (
|
||||
github.com/eclipse/paho.mqtt.golang v1.3.5
|
||||
github.com/go-playground/validator/v10 v10.10.0
|
||||
github.com/golang-jwt/jwt/v4 v4.2.0
|
||||
github.com/golang-jwt/jwt/v4 v4.3.0
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gorilla/handlers v1.5.1
|
||||
|
@ -27,7 +27,7 @@ require (
|
|||
google.golang.org/genproto v0.0.0-20210201151548-94839c025ad4 // indirect
|
||||
google.golang.org/grpc v1.44.0
|
||||
google.golang.org/protobuf v1.27.1
|
||||
gopkg.in/ini.v1 v1.66.3
|
||||
gopkg.in/ini.v1 v1.66.4
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||
)
|
||||
|
||||
|
@ -46,10 +46,13 @@ require (
|
|||
github.com/google/go-cmp v0.5.5 // indirect
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 // indirect
|
||||
github.com/kr/pretty v0.3.0 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/mdlayher/genetlink v1.0.0 // indirect
|
||||
github.com/mdlayher/netlink v1.4.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.8.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.0.1 // indirect
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
|
||||
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
|
||||
|
|
8
go.sum
8
go.sum
|
@ -46,8 +46,8 @@ github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/j
|
|||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||
github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0=
|
||||
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
||||
github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU=
|
||||
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||
github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog=
|
||||
github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
|
@ -299,8 +299,8 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
|
|||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/ini.v1 v1.66.3 h1:jRskFVxYaMGAMUbN0UZ7niA9gzL9B49DOqE78vg0k3w=
|
||||
gopkg.in/ini.v1 v1.66.3/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4=
|
||||
gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
@ -4,44 +4,26 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TimeFormatDay - format of the day for timestamps
|
||||
const TimeFormatDay = "2006-01-02"
|
||||
|
||||
// TimeFormat - total time format
|
||||
const TimeFormat = "2006-01-02 15:04:05"
|
||||
|
||||
// == fields ==
|
||||
var currentLogs = make(map[string]string)
|
||||
|
||||
func makeString(message ...string) string {
|
||||
return strings.Join(message, " ")
|
||||
}
|
||||
|
||||
func getVerbose() int32 {
|
||||
level, err := strconv.Atoi(os.Getenv("VERBOSITY"))
|
||||
if err != nil || level < 0 {
|
||||
level = 0
|
||||
}
|
||||
if level > 3 {
|
||||
level = 3
|
||||
}
|
||||
return int32(level)
|
||||
}
|
||||
|
||||
// ResetLogs - reallocates logs map
|
||||
func ResetLogs() {
|
||||
currentLogs = make(map[string]string)
|
||||
}
|
||||
var mu sync.Mutex
|
||||
|
||||
// Log - handles adding logs
|
||||
func Log(verbosity int, message ...string) {
|
||||
var mu sync.Mutex
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
var currentTime = time.Now()
|
||||
var currentMessage = makeString(message...)
|
||||
var currentMessage = MakeString(" ", message...)
|
||||
if int32(verbosity) <= getVerbose() && getVerbose() >= 0 {
|
||||
fmt.Printf("[netmaker] %s %s \n", currentTime.Format(TimeFormat), currentMessage)
|
||||
}
|
||||
|
@ -74,9 +56,10 @@ func Dump() string {
|
|||
|
||||
for i := range dumpLogs {
|
||||
var currLog = dumpLogs[i]
|
||||
dumpString += fmt.Sprintf("[netmaker] %s %s \n", currLog.Value.Format(TimeFormat), currLog.Key)
|
||||
dumpString += MakeString(" ", "[netmaker]", currLog.Value.Format(TimeFormat), currLog.Key, "\n")
|
||||
}
|
||||
|
||||
resetLogs()
|
||||
return dumpString
|
||||
}
|
||||
|
||||
|
@ -84,13 +67,14 @@ func Dump() string {
|
|||
func DumpFile(filePath string) {
|
||||
f, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
fmt.Println(MakeString(" ", "could not open log file", filePath))
|
||||
return
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
||||
if _, err = f.WriteString(Dump()); err != nil {
|
||||
panic(err)
|
||||
fmt.Println("could not dump logs")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,6 +92,13 @@ func FatalLog(message ...string) {
|
|||
var mu sync.Mutex
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
fmt.Printf("[netmaker] Fatal: %s \n", makeString(message...))
|
||||
fmt.Printf("[netmaker] Fatal: %s \n", MakeString(" ", message...))
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
// == private ==
|
||||
|
||||
// resetLogs - reallocates logs map
|
||||
func resetLogs() {
|
||||
currentLogs = make(map[string]string)
|
||||
}
|
||||
|
|
30
logger/util.go
Normal file
30
logger/util.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
package logger
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// MakeString - makes a string using golang string builder
|
||||
func MakeString(delimeter string, message ...string) string {
|
||||
var builder strings.Builder
|
||||
for i := range message {
|
||||
builder.WriteString(message[i])
|
||||
if delimeter != "" && i != len(message)-1 {
|
||||
builder.WriteString(delimeter)
|
||||
}
|
||||
}
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
func getVerbose() int32 {
|
||||
level, err := strconv.Atoi(os.Getenv("VERBOSITY"))
|
||||
if err != nil || level < 0 {
|
||||
level = 0
|
||||
}
|
||||
if level > 3 {
|
||||
level = 3
|
||||
}
|
||||
return int32(level)
|
||||
}
|
|
@ -49,18 +49,17 @@ func CreateAccessKey(accesskey models.AccessKey, network models.Network) (models
|
|||
|
||||
netID := network.NetID
|
||||
|
||||
commsNetID, err := FetchCommsNetID()
|
||||
if err != nil {
|
||||
return models.AccessKey{}, errors.New("could not retrieve comms netid")
|
||||
}
|
||||
|
||||
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,
|
||||
GRPCConnString: s.GRPCConnString,
|
||||
GRPCSSL: s.GRPCSSL,
|
||||
CommsNetwork: commsNetID,
|
||||
}
|
||||
accessToken.ServerConfig = servervals
|
||||
accessToken.ClientConfig.Network = netID
|
||||
|
@ -148,7 +147,7 @@ func DecrimentKey(networkName string, keyvalue string) {
|
|||
var network models.Network
|
||||
|
||||
network, err := GetParentNetwork(networkName)
|
||||
if err != nil {
|
||||
if err != nil || network.IsComms == "yes" {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -176,13 +175,21 @@ func DecrimentKey(networkName string, keyvalue string) {
|
|||
// IsKeyValid - check if key is valid
|
||||
func IsKeyValid(networkname string, keyvalue string) bool {
|
||||
|
||||
network, _ := GetParentNetwork(networkname)
|
||||
network, err := GetParentNetwork(networkname)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
accesskeys := network.AccessKeys
|
||||
if network.IsComms == "yes" {
|
||||
accesskeys = getAllAccessKeys()
|
||||
}
|
||||
|
||||
var key models.AccessKey
|
||||
foundkey := false
|
||||
isvalid := false
|
||||
|
||||
for i := len(network.AccessKeys) - 1; i >= 0; i-- {
|
||||
currentkey := network.AccessKeys[i]
|
||||
for i := len(accesskeys) - 1; i >= 0; i-- {
|
||||
currentkey := accesskeys[i]
|
||||
if currentkey.Value == keyvalue {
|
||||
key = currentkey
|
||||
foundkey = true
|
||||
|
@ -236,3 +243,15 @@ func genKey() string {
|
|||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func getAllAccessKeys() []models.AccessKey {
|
||||
var accesskeys = make([]models.AccessKey, 0)
|
||||
networks, err := GetNetworks()
|
||||
if err != nil {
|
||||
return accesskeys
|
||||
}
|
||||
for i := range networks {
|
||||
accesskeys = append(accesskeys, networks[i].AccessKeys...)
|
||||
}
|
||||
return accesskeys
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"github.com/txn2/txeh"
|
||||
)
|
||||
|
||||
|
@ -39,9 +38,12 @@ func SetDNS() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
/* if something goes wrong with server DNS, check here
|
||||
// commented out bc we were not using IsSplitDNS
|
||||
if servercfg.IsSplitDNS() {
|
||||
err = SetCorefile(corefilestring)
|
||||
}
|
||||
*/
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,6 @@ func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, erro
|
|||
node.PostUp = postUpCmd
|
||||
node.PostDown = postDownCmd
|
||||
node.SetLastModified()
|
||||
node.PullChanges = "yes"
|
||||
nodeData, err := json.Marshal(&node)
|
||||
if err != nil {
|
||||
return node, err
|
||||
|
@ -94,7 +93,6 @@ func DeleteEgressGateway(network, nodeid string) (models.Node, error) {
|
|||
node.PostDown = "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -D POSTROUTING -o " + node.Interface + " -j MASQUERADE"
|
||||
}
|
||||
node.SetLastModified()
|
||||
node.PullChanges = "yes"
|
||||
|
||||
data, err := json.Marshal(&node)
|
||||
if err != nil {
|
||||
|
@ -142,7 +140,6 @@ func CreateIngressGateway(netid string, nodeid string) (models.Node, error) {
|
|||
node.SetLastModified()
|
||||
node.PostUp = postUpCmd
|
||||
node.PostDown = postDownCmd
|
||||
node.PullChanges = "yes"
|
||||
node.UDPHolePunch = "no"
|
||||
|
||||
data, err := json.Marshal(&node)
|
||||
|
@ -177,7 +174,6 @@ func DeleteIngressGateway(networkName string, nodeid string) (models.Node, error
|
|||
node.LastModified = time.Now().Unix()
|
||||
node.IsIngressGateway = "no"
|
||||
node.IngressGatewayRange = ""
|
||||
node.PullChanges = "yes"
|
||||
|
||||
data, err := json.Marshal(&node)
|
||||
if err != nil {
|
||||
|
|
|
@ -80,7 +80,7 @@ func CreateUserJWT(username string, networks []string, isadmin bool) (response s
|
|||
func VerifyUserToken(tokenString string) (username string, networks []string, isadmin bool, err error) {
|
||||
claims := &models.UserClaims{}
|
||||
|
||||
if tokenString == servercfg.GetMasterKey() {
|
||||
if tokenString == servercfg.GetMasterKey() && servercfg.GetMasterKey() != "" {
|
||||
return "masteradministrator", nil, true, nil
|
||||
}
|
||||
|
||||
|
@ -104,7 +104,7 @@ func VerifyToken(tokenString string) (nodeID string, mac string, network string,
|
|||
|
||||
//this may be a stupid way of serving up a master key
|
||||
//TODO: look into a different method. Encryption?
|
||||
if tokenString == servercfg.GetMasterKey() {
|
||||
if tokenString == servercfg.GetMasterKey() && servercfg.GetMasterKey() != "" {
|
||||
return "mastermac", "", "", nil
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
"net"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
|
@ -68,7 +67,6 @@ func CreateNetwork(network models.Network) error {
|
|||
network.SetDefaults()
|
||||
network.SetNodesLastModified()
|
||||
network.SetNetworkLastModified()
|
||||
network.KeyUpdateTimeStamp = time.Now().Unix()
|
||||
|
||||
err := ValidateNetwork(&network, false)
|
||||
if err != nil {
|
||||
|
@ -106,7 +104,6 @@ func NetworkNodesUpdatePullChanges(networkName string) error {
|
|||
return err
|
||||
}
|
||||
if node.Network == networkName {
|
||||
node.PullChanges = "yes"
|
||||
data, err := json.Marshal(&node)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -190,19 +187,13 @@ func UniqueAddress(networkName string) (string, error) {
|
|||
offset = false
|
||||
continue
|
||||
}
|
||||
if networkName == "comms" {
|
||||
if IsIPUnique(networkName, ip.String(), database.INT_CLIENTS_TABLE_NAME, false) {
|
||||
return ip.String(), err
|
||||
}
|
||||
} else {
|
||||
if IsIPUnique(networkName, ip.String(), database.NODES_TABLE_NAME, false) && IsIPUnique(networkName, ip.String(), database.EXT_CLIENT_TABLE_NAME, false) {
|
||||
return ip.String(), err
|
||||
}
|
||||
if IsIPUnique(networkName, ip.String(), database.NODES_TABLE_NAME, false) && IsIPUnique(networkName, ip.String(), database.EXT_CLIENT_TABLE_NAME, false) {
|
||||
return ip.String(), err
|
||||
}
|
||||
}
|
||||
|
||||
//TODO
|
||||
err1 := errors.New("ERROR: No unique addresses available. Check network subnet.")
|
||||
err1 := errors.New("ERROR: No unique addresses available. Check network subnet")
|
||||
return "W1R3: NO UNIQUE ADDRESSES AVAILABLE", err1
|
||||
}
|
||||
|
||||
|
@ -301,7 +292,7 @@ func UniqueAddress6(networkName string) (string, error) {
|
|||
}
|
||||
}
|
||||
//TODO
|
||||
err1 := errors.New("ERROR: No unique addresses available. Check network subnet.")
|
||||
err1 := errors.New("ERROR: No unique addresses available. Check network subnet")
|
||||
return "W1R3: NO UNIQUE ADDRESSES AVAILABLE", err1
|
||||
}
|
||||
|
||||
|
@ -380,7 +371,13 @@ func UpdateNetworkLocalAddresses(networkName string) error {
|
|||
return err
|
||||
}
|
||||
if node.Network == networkName {
|
||||
ipaddr, iperr := UniqueAddress(networkName)
|
||||
var ipaddr string
|
||||
var iperr error
|
||||
if node.IsServer == "yes" {
|
||||
ipaddr, iperr = UniqueAddressServer(networkName)
|
||||
} else {
|
||||
ipaddr, iperr = UniqueAddress(networkName)
|
||||
}
|
||||
if iperr != nil {
|
||||
fmt.Println("error in node address assignment!")
|
||||
return iperr
|
||||
|
@ -440,7 +437,6 @@ func RemoveNetworkNodeIPv6Addresses(networkName string) error {
|
|||
if node.Network == networkName {
|
||||
node.IsDualStack = "no"
|
||||
node.Address6 = ""
|
||||
node.PullChanges = "yes"
|
||||
data, err := json.Marshal(&node)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -469,14 +465,19 @@ func UpdateNetworkNodeAddresses(networkName string) error {
|
|||
return err
|
||||
}
|
||||
if node.Network == networkName {
|
||||
ipaddr, iperr := UniqueAddress(networkName)
|
||||
var ipaddr string
|
||||
var iperr error
|
||||
if node.IsServer == "yes" {
|
||||
ipaddr, iperr = UniqueAddressServer(networkName)
|
||||
} else {
|
||||
ipaddr, iperr = UniqueAddress(networkName)
|
||||
}
|
||||
if iperr != nil {
|
||||
fmt.Println("error in node address assignment!")
|
||||
return iperr
|
||||
}
|
||||
|
||||
node.Address = ipaddr
|
||||
node.PullChanges = "yes"
|
||||
data, err := json.Marshal(&node)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -488,27 +489,6 @@ func UpdateNetworkNodeAddresses(networkName string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// IsNetworkDisplayNameUnique - checks if displayname is unique from other networks
|
||||
func IsNetworkDisplayNameUnique(network *models.Network) (bool, error) {
|
||||
|
||||
isunique := true
|
||||
|
||||
records, err := GetNetworks()
|
||||
|
||||
if err != nil && !database.IsEmptyRecord(err) {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for i := 0; i < len(records); i++ {
|
||||
|
||||
if network.NetID == records[i].DisplayName {
|
||||
isunique = false
|
||||
}
|
||||
}
|
||||
|
||||
return isunique, nil
|
||||
}
|
||||
|
||||
// IsNetworkNameUnique - checks to see if any other networks have the same name (id)
|
||||
func IsNetworkNameUnique(network *models.Network) (bool, error) {
|
||||
|
||||
|
@ -600,14 +580,6 @@ func ValidateNetwork(network *models.Network, isUpdate bool) error {
|
|||
return isFieldUnique && inCharSet
|
||||
})
|
||||
//
|
||||
_ = v.RegisterValidation("displayname_valid", func(fl validator.FieldLevel) bool {
|
||||
isFieldUnique, _ := IsNetworkDisplayNameUnique(network)
|
||||
inCharSet := network.DisplayNameInNetworkCharSet()
|
||||
if isUpdate {
|
||||
return inCharSet
|
||||
}
|
||||
return isFieldUnique && inCharSet
|
||||
})
|
||||
_ = v.RegisterValidation("checkyesorno", func(fl validator.FieldLevel) bool {
|
||||
return validation.CheckYesOrNo(fl)
|
||||
})
|
||||
|
|
|
@ -85,7 +85,6 @@ func UncordonNode(nodeid string) (models.Node, error) {
|
|||
}
|
||||
node.SetLastModified()
|
||||
node.IsPending = "no"
|
||||
node.PullChanges = "yes"
|
||||
data, err := json.Marshal(&node)
|
||||
if err != nil {
|
||||
return node, err
|
||||
|
@ -100,12 +99,7 @@ func GetPeers(node *models.Node) ([]models.Node, error) {
|
|||
if 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)
|
||||
peers, err := GetPeersList(node)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), RELAY_NODE_ERR) {
|
||||
peers, err = PeerListUnRelay(node.ID, node.Network)
|
||||
|
@ -145,6 +139,13 @@ func IsLeader(node *models.Node) bool {
|
|||
|
||||
// UpdateNode - takes a node and updates another node with it's values
|
||||
func UpdateNode(currentNode *models.Node, newNode *models.Node) error {
|
||||
var err error
|
||||
if newNode.IsHub == "yes" && currentNode.IsHub != "yes" {
|
||||
if err = unsetHub(newNode.Network); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if newNode.Address != currentNode.Address {
|
||||
if network, err := GetParentNetwork(newNode.Network); err == nil {
|
||||
if !IsAddressInCIDR(newNode.Address, network.AddressRange) {
|
||||
|
@ -350,13 +351,7 @@ func SetNodeDefaults(node *models.Node) {
|
|||
if node.ListenPort == 0 {
|
||||
node.ListenPort = parentNetwork.DefaultListenPort
|
||||
}
|
||||
if node.SaveConfig == "" {
|
||||
if parentNetwork.DefaultSaveConfig != "" {
|
||||
node.SaveConfig = parentNetwork.DefaultSaveConfig
|
||||
} else {
|
||||
node.SaveConfig = "yes"
|
||||
}
|
||||
}
|
||||
|
||||
if node.Interface == "" {
|
||||
node.Interface = parentNetwork.DefaultInterface
|
||||
}
|
||||
|
@ -396,8 +391,6 @@ func SetNodeDefaults(node *models.Node) {
|
|||
node.SetDefaultName()
|
||||
node.SetLastCheckIn()
|
||||
node.SetLastPeerUpdate()
|
||||
node.SetRoamingDefault()
|
||||
node.SetPullChangesDefault()
|
||||
node.SetDefaultAction()
|
||||
node.SetIsServerDefault()
|
||||
node.SetIsStaticDefault()
|
||||
|
@ -409,7 +402,7 @@ func SetNodeDefaults(node *models.Node) {
|
|||
node.SetDefaultIsRelay()
|
||||
node.SetDefaultIsDocker()
|
||||
node.SetDefaultIsK8S()
|
||||
node.KeyUpdateTimeStamp = time.Now().Unix()
|
||||
node.SetDefaultIsHub()
|
||||
}
|
||||
|
||||
// GetRecordKey - get record key
|
||||
|
@ -512,32 +505,6 @@ func GetNodeRelay(network string, relayedNodeAddr string) (models.Node, error) {
|
|||
return relay, errors.New(RELAY_NODE_ERR + " " + relayedNodeAddr)
|
||||
}
|
||||
|
||||
// GetNodeByIDorMacAddress - gets the node, if a mac address exists, but not id, then it should delete it and recreate in DB with new ID
|
||||
/*
|
||||
func GetNodeByIDorMacAddress(uuid string, macaddress string, network string) (models.Node, error) {
|
||||
var node models.Node
|
||||
var err error
|
||||
node, err = GetNodeByID(uuid)
|
||||
if err != nil && macaddress != "" && network != "" {
|
||||
node, err = GetNodeByMacAddress(network, macaddress)
|
||||
if err != nil {
|
||||
return models.Node{}, err
|
||||
}
|
||||
err = DeleteNodeByMacAddress(&node, true) // remove node
|
||||
if err != nil {
|
||||
return models.Node{}, err
|
||||
}
|
||||
err = CreateNode(&node)
|
||||
if err != nil {
|
||||
return models.Node{}, err
|
||||
}
|
||||
logger.Log(2, "rewriting legacy node data; node now has id,", node.ID)
|
||||
node.PullChanges = "yes"
|
||||
}
|
||||
return node, err
|
||||
}
|
||||
*/
|
||||
// GetNodeByID - get node by uuid, should have been set by create
|
||||
func GetNodeByID(uuid string) (models.Node, error) {
|
||||
var record, err = database.FetchRecord(database.NODES_TABLE_NAME, uuid)
|
||||
if err != nil {
|
||||
|
@ -611,6 +578,11 @@ func IsLocalServer(node *models.Node) bool {
|
|||
return node.ID != "" && local.ID == node.ID
|
||||
}
|
||||
|
||||
// IsNodeInComms returns if node is in comms network or not
|
||||
func IsNodeInComms(node *models.Node) bool {
|
||||
return node.Network == servercfg.GetCommsID() && node.IsServer != "yes"
|
||||
}
|
||||
|
||||
// validateServer - make sure servers dont change port or address
|
||||
func validateServer(currentNode, newNode *models.Node) bool {
|
||||
return (newNode.Address == currentNode.Address &&
|
||||
|
@ -640,3 +612,25 @@ func isMacAddressUnique(macaddress string, networkName string) (bool, error) {
|
|||
|
||||
return isunique, nil
|
||||
}
|
||||
|
||||
// unsetHub - unset hub on network nodes
|
||||
func unsetHub(networkName string) error {
|
||||
|
||||
nodes, err := GetNetworkNodes(networkName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range nodes {
|
||||
if nodes[i].IsHub == "yes" {
|
||||
nodes[i].IsHub = "no"
|
||||
newNodeData, err := json.Marshal(&nodes[i])
|
||||
if err != nil {
|
||||
logger.Log(1, "error on node during hub update")
|
||||
return err
|
||||
}
|
||||
database.Insert(nodes[i].ID, string(newNodeData), database.NODES_TABLE_NAME)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
130
logic/peers.go
130
logic/peers.go
|
@ -7,12 +7,142 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/netclient/ncutils"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
|
||||
// GetHubPeer - in HubAndSpoke networks, if not the hub, return the hub
|
||||
/*
|
||||
func GetHubPeer(networkName string) []models.Node {
|
||||
var hubpeer = make([]models.Node, 0)
|
||||
servernodes, err := GetNetworkNodes(networkName)
|
||||
if err != nil {
|
||||
return hubpeer
|
||||
}
|
||||
for i := range servernodes {
|
||||
if servernodes[i].IsHub == "yes" {
|
||||
return []models.Node{servernodes[i]}
|
||||
}
|
||||
}
|
||||
return hubpeer
|
||||
}
|
||||
*/
|
||||
|
||||
// GetNodePeers - fetches peers for a given node
|
||||
func GetNodePeers(networkName string, excludeRelayed bool, isP2S bool) ([]models.Node, error) {
|
||||
var peers []models.Node
|
||||
var networkNodes, egressNetworkNodes, err = getNetworkEgressAndNodes(networkName)
|
||||
if err != nil {
|
||||
return peers, nil
|
||||
}
|
||||
|
||||
udppeers, errN := database.GetPeers(networkName)
|
||||
if errN != nil {
|
||||
logger.Log(2, errN.Error())
|
||||
}
|
||||
|
||||
for _, node := range networkNodes {
|
||||
var peer = models.Node{}
|
||||
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 := GetNetwork(networkName)
|
||||
if err == nil {
|
||||
peer.AllowedIPs = append(peer.AllowedIPs, network.AddressRange)
|
||||
} else {
|
||||
peer.AllowedIPs = append(peer.AllowedIPs, node.RelayAddrs...)
|
||||
}
|
||||
for _, egressNode := range egressNetworkNodes {
|
||||
if egressNode.IsRelayed == "yes" && StringSliceContains(node.RelayAddrs, egressNode.Address) {
|
||||
peer.AllowedIPs = append(peer.AllowedIPs, egressNode.EgressGatewayRanges...)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !isP2S || peer.IsHub == "yes" {
|
||||
peers = append(peers, peer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return peers, err
|
||||
}
|
||||
|
||||
// GetPeersList - gets the peers of a given network
|
||||
func GetPeersList(refnode *models.Node) ([]models.Node, error) {
|
||||
var peers []models.Node
|
||||
var err error
|
||||
var isP2S bool
|
||||
var networkName = refnode.Network
|
||||
var excludeRelayed = refnode.IsRelay != "yes"
|
||||
var relayedNodeAddr string
|
||||
if refnode.IsRelayed == "yes" {
|
||||
relayedNodeAddr = refnode.Address
|
||||
}
|
||||
|
||||
network, err := GetNetwork(networkName)
|
||||
if err != nil {
|
||||
return peers, err
|
||||
} else if network.IsPointToSite == "yes" && refnode.IsHub != "yes" {
|
||||
isP2S = true
|
||||
}
|
||||
if relayedNodeAddr == "" {
|
||||
peers, err = GetNodePeers(networkName, excludeRelayed, isP2S)
|
||||
} else {
|
||||
var relayNode models.Node
|
||||
relayNode, err = GetNodeRelay(networkName, relayedNodeAddr)
|
||||
if relayNode.Address != "" {
|
||||
var peerNode = setPeerInfo(&relayNode)
|
||||
network, err := GetNetwork(networkName)
|
||||
if err == nil {
|
||||
peerNode.AllowedIPs = append(peerNode.AllowedIPs, network.AddressRange)
|
||||
var _, egressNetworkNodes, err = getNetworkEgressAndNodes(networkName)
|
||||
if err == nil {
|
||||
for _, egress := range egressNetworkNodes {
|
||||
if egress.Address != relayedNodeAddr {
|
||||
peerNode.AllowedIPs = append(peerNode.AllowedIPs, egress.EgressGatewayRanges...)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
peerNode.AllowedIPs = append(peerNode.AllowedIPs, peerNode.RelayAddrs...)
|
||||
}
|
||||
nodepeers, err := GetNodePeers(networkName, false, isP2S)
|
||||
if err == nil && peerNode.UDPHolePunch == "yes" {
|
||||
for _, nodepeer := range nodepeers {
|
||||
if nodepeer.Address == peerNode.Address {
|
||||
// peerNode.Endpoint = nodepeer.Endpoint
|
||||
peerNode.ListenPort = nodepeer.ListenPort
|
||||
}
|
||||
}
|
||||
}
|
||||
if !isP2S || peerNode.IsHub == "yes" {
|
||||
peers = append(peers, peerNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
return peers, err
|
||||
}
|
||||
|
||||
// GetPeerUpdate - gets a wireguard peer config for each peer of a node
|
||||
func GetPeerUpdate(node *models.Node) (models.PeerUpdate, error) {
|
||||
var peerUpdate models.PeerUpdate
|
||||
|
|
|
@ -30,7 +30,6 @@ func CreateRelay(relay models.RelayRequest) ([]models.Node, models.Node, error)
|
|||
node.RelayAddrs = relay.RelayAddrs
|
||||
|
||||
node.SetLastModified()
|
||||
node.PullChanges = "yes"
|
||||
nodeData, err := json.Marshal(&node)
|
||||
if err != nil {
|
||||
return returnnodes, node, err
|
||||
|
@ -90,14 +89,14 @@ func SetRelayedNodes(yesOrno string, networkName string, addrs []string) ([]mode
|
|||
}
|
||||
|
||||
// SetNodeIsRelayed - Sets IsRelayed to on or off for relay
|
||||
func SetNodeIsRelayed(yesOrno string, id string) error {
|
||||
func SetNodeIsRelayed(yesOrno string, id string) (models.Node, error) {
|
||||
node, err := GetNodeByID(id)
|
||||
if err != nil {
|
||||
return err
|
||||
return node, err
|
||||
}
|
||||
network, err := GetNetworkByNode(&node)
|
||||
if err != nil {
|
||||
return err
|
||||
return node, err
|
||||
}
|
||||
node.IsRelayed = yesOrno
|
||||
if yesOrno == "yes" {
|
||||
|
@ -107,18 +106,18 @@ func SetNodeIsRelayed(yesOrno string, id string) error {
|
|||
}
|
||||
data, err := json.Marshal(&node)
|
||||
if err != nil {
|
||||
return err
|
||||
return node, err
|
||||
}
|
||||
return database.Insert(node.ID, string(data), database.NODES_TABLE_NAME)
|
||||
return node, database.Insert(node.ID, string(data), database.NODES_TABLE_NAME)
|
||||
}
|
||||
|
||||
// PeerListUnRelay - call this function if a relayed node fails to get its relay: unrelays node and gets new peer list
|
||||
func PeerListUnRelay(id string, network string) ([]models.Node, error) {
|
||||
err := SetNodeIsRelayed("no", id)
|
||||
node, err := SetNodeIsRelayed("no", id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return GetPeersList(network, true, "")
|
||||
return GetPeersList(&node)
|
||||
}
|
||||
|
||||
// ValidateRelay - checks if relay is valid
|
||||
|
@ -162,7 +161,6 @@ func DeleteRelay(network, nodeid string) ([]models.Node, models.Node, error) {
|
|||
node.IsRelay = "no"
|
||||
node.RelayAddrs = []string{}
|
||||
node.SetLastModified()
|
||||
node.PullChanges = "yes"
|
||||
|
||||
data, err := json.Marshal(&node)
|
||||
if err != nil {
|
||||
|
|
|
@ -39,7 +39,24 @@ func ServerJoin(networkSettings *models.Network) (models.Node, error) {
|
|||
if currentServers != nil {
|
||||
serverCount = len(currentServers) + 1
|
||||
}
|
||||
var ishub = "no"
|
||||
|
||||
if networkSettings.IsPointToSite == "yes" || networkSettings.IsComms == "yes" {
|
||||
nodes, err := GetNetworkNodes(networkSettings.NetID)
|
||||
if err != nil || nodes == nil {
|
||||
ishub = "yes"
|
||||
} else {
|
||||
sethub := true
|
||||
for i := range nodes {
|
||||
if nodes[i].IsHub == "yes" {
|
||||
sethub = false
|
||||
}
|
||||
}
|
||||
if sethub {
|
||||
ishub = "yes"
|
||||
}
|
||||
}
|
||||
}
|
||||
var node = &models.Node{
|
||||
IsServer: "yes",
|
||||
DNSOn: "no",
|
||||
|
@ -52,6 +69,7 @@ func ServerJoin(networkSettings *models.Network) (models.Node, error) {
|
|||
LocalRange: networkSettings.LocalRange,
|
||||
OS: runtime.GOOS,
|
||||
Version: servercfg.Version,
|
||||
IsHub: ishub,
|
||||
}
|
||||
|
||||
SetNodeDefaults(node)
|
||||
|
@ -389,7 +407,7 @@ func ServerPull(serverNode *models.Node, ifaceDelta bool) error {
|
|||
}
|
||||
serverNode.OS = runtime.GOOS
|
||||
|
||||
if serverNode.PullChanges == "yes" || ifaceDelta {
|
||||
if ifaceDelta {
|
||||
// check for interface change
|
||||
// checks if address is in use by another interface
|
||||
var oldIfaceName, isIfacePresent = isInterfacePresent(serverNode.Interface, serverNode.Address)
|
||||
|
@ -399,7 +417,6 @@ func ServerPull(serverNode *models.Node, ifaceDelta bool) error {
|
|||
}
|
||||
logger.Log(1, "removed old interface", oldIfaceName)
|
||||
}
|
||||
serverNode.PullChanges = "no"
|
||||
if err = setWGConfig(serverNode, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -72,3 +72,32 @@ func StoreJWTSecret(privateKey string) error {
|
|||
}
|
||||
return database.Insert("nm-jwt-secret", string(data), database.SERVERCONF_TABLE_NAME)
|
||||
}
|
||||
|
||||
// FetchCommsNetID - fetches comms netid from db
|
||||
func FetchCommsNetID() (string, error) {
|
||||
var dbData string
|
||||
var err error
|
||||
var fetchedData = serverData{}
|
||||
dbData, err = database.FetchRecord(database.SERVERCONF_TABLE_NAME, "nm-comms-id")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = json.Unmarshal([]byte(dbData), &fetchedData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fetchedData.PrivateKey, nil
|
||||
}
|
||||
|
||||
// StoreCommsNetID - stores server comms network netid if needed
|
||||
func StoreCommsNetID(netid string) error {
|
||||
var newData = serverData{}
|
||||
var err error
|
||||
var data []byte
|
||||
newData.PrivateKey = netid
|
||||
data, err = json.Marshal(&newData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return database.Insert("nm-comms-id", string(data), database.SERVERCONF_TABLE_NAME)
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -130,101 +129,6 @@ func DeleteNodeByID(node *models.Node, exterminate bool) error {
|
|||
return removeLocalServer(node)
|
||||
}
|
||||
|
||||
// GetNodePeers - fetches peers for a given node
|
||||
func GetNodePeers(networkName string, excludeRelayed bool) ([]models.Node, error) {
|
||||
var peers []models.Node
|
||||
var networkNodes, egressNetworkNodes, err = getNetworkEgressAndNodes(networkName)
|
||||
if err != nil {
|
||||
return peers, nil
|
||||
}
|
||||
|
||||
udppeers, errN := database.GetPeers(networkName)
|
||||
if errN != nil {
|
||||
logger.Log(2, errN.Error())
|
||||
}
|
||||
|
||||
for _, node := range networkNodes {
|
||||
var peer = models.Node{}
|
||||
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 := GetNetwork(networkName)
|
||||
if err == nil {
|
||||
peer.AllowedIPs = append(peer.AllowedIPs, network.AddressRange)
|
||||
} else {
|
||||
peer.AllowedIPs = append(peer.AllowedIPs, node.RelayAddrs...)
|
||||
}
|
||||
for _, egressNode := range egressNetworkNodes {
|
||||
if egressNode.IsRelayed == "yes" && StringSliceContains(node.RelayAddrs, egressNode.Address) {
|
||||
peer.AllowedIPs = append(peer.AllowedIPs, egressNode.EgressGatewayRanges...)
|
||||
}
|
||||
}
|
||||
}
|
||||
peers = append(peers, peer)
|
||||
}
|
||||
}
|
||||
|
||||
return peers, err
|
||||
}
|
||||
|
||||
// GetPeersList - gets the peers of a given network
|
||||
func GetPeersList(networkName string, excludeRelayed bool, relayedNodeAddr string) ([]models.Node, error) {
|
||||
var peers []models.Node
|
||||
var err error
|
||||
if relayedNodeAddr == "" {
|
||||
peers, err = GetNodePeers(networkName, excludeRelayed)
|
||||
} else {
|
||||
var relayNode models.Node
|
||||
relayNode, err = GetNodeRelay(networkName, relayedNodeAddr)
|
||||
if relayNode.Address != "" {
|
||||
var peerNode = setPeerInfo(&relayNode)
|
||||
network, err := GetNetwork(networkName)
|
||||
if err == nil {
|
||||
peerNode.AllowedIPs = append(peerNode.AllowedIPs, network.AddressRange)
|
||||
var _, egressNetworkNodes, err = getNetworkEgressAndNodes(networkName)
|
||||
if err == nil {
|
||||
for _, egress := range egressNetworkNodes {
|
||||
if egress.Address != relayedNodeAddr {
|
||||
peerNode.AllowedIPs = append(peerNode.AllowedIPs, egress.EgressGatewayRanges...)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
peerNode.AllowedIPs = append(peerNode.AllowedIPs, peerNode.RelayAddrs...)
|
||||
}
|
||||
nodepeers, err := GetNodePeers(networkName, false)
|
||||
if err == nil && peerNode.UDPHolePunch == "yes" {
|
||||
for _, nodepeer := range nodepeers {
|
||||
if nodepeer.Address == peerNode.Address {
|
||||
// peerNode.Endpoint = nodepeer.Endpoint
|
||||
peerNode.ListenPort = nodepeer.ListenPort
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
peers = append(peers, peerNode)
|
||||
}
|
||||
}
|
||||
return peers, err
|
||||
}
|
||||
|
||||
// RandomString - returns a random string in a charset
|
||||
func RandomString(length int) string {
|
||||
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
|
@ -283,6 +187,7 @@ func setPeerInfo(node *models.Node) models.Node {
|
|||
peer.UDPHolePunch = node.UDPHolePunch
|
||||
peer.Address = node.Address
|
||||
peer.Address6 = node.Address6
|
||||
peer.IsHub = node.IsHub
|
||||
peer.EgressGatewayRanges = node.EgressGatewayRanges
|
||||
peer.IsEgressGateway = node.IsEgressGateway
|
||||
peer.IngressGatewayRange = node.IngressGatewayRange
|
||||
|
|
|
@ -46,6 +46,63 @@ func HasPeerConnected(node *models.Node) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// IfaceDelta - checks if the new node causes an interface change
|
||||
func IfaceDelta(currentNode *models.Node, newNode *models.Node) bool {
|
||||
// single comparison statements
|
||||
if newNode.Endpoint != currentNode.Endpoint ||
|
||||
newNode.LocalAddress != currentNode.LocalAddress ||
|
||||
newNode.PublicKey != currentNode.PublicKey ||
|
||||
newNode.Address != currentNode.Address ||
|
||||
newNode.IsEgressGateway != currentNode.IsEgressGateway ||
|
||||
newNode.IsIngressGateway != currentNode.IsIngressGateway ||
|
||||
newNode.IsRelay != currentNode.IsRelay ||
|
||||
newNode.UDPHolePunch != currentNode.UDPHolePunch ||
|
||||
newNode.IsPending != currentNode.IsPending ||
|
||||
newNode.ListenPort != currentNode.ListenPort ||
|
||||
newNode.MTU != currentNode.MTU ||
|
||||
newNode.PersistentKeepalive != currentNode.PersistentKeepalive ||
|
||||
newNode.DNSOn != currentNode.DNSOn ||
|
||||
len(newNode.AllowedIPs) != len(currentNode.AllowedIPs) {
|
||||
return true
|
||||
}
|
||||
|
||||
// multi-comparison statements
|
||||
if newNode.IsDualStack == "yes" {
|
||||
if newNode.Address6 != currentNode.Address6 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if newNode.IsEgressGateway == "yes" {
|
||||
if len(currentNode.EgressGatewayRanges) != len(newNode.EgressGatewayRanges) {
|
||||
return true
|
||||
}
|
||||
for _, address := range newNode.EgressGatewayRanges {
|
||||
if !StringSliceContains(currentNode.EgressGatewayRanges, address) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if newNode.IsRelay == "yes" {
|
||||
if len(currentNode.RelayAddrs) != len(newNode.RelayAddrs) {
|
||||
return true
|
||||
}
|
||||
for _, address := range newNode.RelayAddrs {
|
||||
if !StringSliceContains(currentNode.RelayAddrs, address) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, address := range newNode.AllowedIPs {
|
||||
if !StringSliceContains(currentNode.AllowedIPs, address) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// == Private Functions ==
|
||||
|
||||
// gets the server peers locally
|
||||
|
|
10
main.go
10
main.go
|
@ -40,6 +40,11 @@ func main() {
|
|||
|
||||
func initialize() { // Client Mode Prereq Check
|
||||
var err error
|
||||
|
||||
if servercfg.GetMasterKey() == "" {
|
||||
logger.Log(0, "warning: MASTER_KEY not set, this could make account recovery difficult")
|
||||
}
|
||||
|
||||
if servercfg.GetNodeID() == "" {
|
||||
logger.FatalLog("error: must set NODE_ID, currently blank")
|
||||
}
|
||||
|
@ -76,6 +81,9 @@ func initialize() { // Client Mode Prereq Check
|
|||
if err := serverctl.InitServerNetclient(); err != nil {
|
||||
logger.FatalLog("Did not find netclient to use CLIENT_MODE")
|
||||
}
|
||||
if err := serverctl.InitializeCommsNetwork(); err != nil {
|
||||
logger.FatalLog("could not inintialize comms network")
|
||||
}
|
||||
}
|
||||
// initialize iptables to ensure gateways work correctly and mq is forwarded if containerized
|
||||
if servercfg.ManageIPTables() != "off" {
|
||||
|
@ -187,7 +195,7 @@ func runGRPC(wg *sync.WaitGroup) {
|
|||
// Should we be using a context vice a waitgroup????????????
|
||||
func runMessageQueue(wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
logger.Log(0, fmt.Sprintf("connecting to mq broker at %s", servercfg.GetMessageQueueEndpoint()))
|
||||
logger.Log(0, "connecting to mq broker at", servercfg.GetMessageQueueEndpoint())
|
||||
var client = mq.SetupMQTT(false) // Set up the subscription listener
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go mq.Keepalive(ctx)
|
||||
|
|
|
@ -3,7 +3,6 @@ package models
|
|||
type AccessToken struct {
|
||||
ServerConfig
|
||||
ClientConfig
|
||||
WG
|
||||
}
|
||||
|
||||
type ClientConfig struct {
|
||||
|
@ -13,21 +12,7 @@ type ClientConfig struct {
|
|||
}
|
||||
|
||||
type ServerConfig struct {
|
||||
CoreDNSAddr string `json:"corednsaddr"`
|
||||
APIConnString string `json:"apiconn"`
|
||||
APIHost string `json:"apihost"`
|
||||
APIPort string `json:"apiport"`
|
||||
GRPCConnString string `json:"grpcconn"`
|
||||
GRPCHost string `json:"grpchost"`
|
||||
GRPCPort string `json:"grpcport"`
|
||||
GRPCSSL string `json:"grpcssl"`
|
||||
CheckinInterval string `json:"checkininterval"`
|
||||
}
|
||||
|
||||
type WG struct {
|
||||
GRPCWireGuard string `json:"grpcwg"`
|
||||
GRPCWGAddress string `json:"grpcwgaddr"`
|
||||
GRPCWGPort string `json:"grpcwgport"`
|
||||
GRPCWGPubKey string `json:"grpcwgpubkey"`
|
||||
GRPCWGEndpoint string `json:"grpcwgendpoint"`
|
||||
GRPCConnString string `json:"grpcconn"`
|
||||
GRPCSSL string `json:"grpcssl"`
|
||||
CommsNetwork string `json:"commsnetwork"`
|
||||
}
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
)
|
||||
|
||||
// Network Struct - contains info for a given unique network
|
||||
|
@ -12,7 +9,6 @@ import (
|
|||
type Network struct {
|
||||
AddressRange string `json:"addressrange" bson:"addressrange" validate:"required,cidr"`
|
||||
AddressRange6 string `json:"addressrange6" bson:"addressrange6" validate:"regexp=^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$"`
|
||||
DisplayName string `json:"displayname,omitempty" bson:"displayname,omitempty" validate:"omitempty,min=1,max=20,displayname_valid"`
|
||||
NetID string `json:"netid" bson:"netid" validate:"required,min=1,max=12,netid_valid"`
|
||||
NodesLastModified int64 `json:"nodeslastmodified" bson:"nodeslastmodified"`
|
||||
NetworkLastModified int64 `json:"networklastmodified" bson:"networklastmodified"`
|
||||
|
@ -21,24 +17,21 @@ type Network struct {
|
|||
NodeLimit int32 `json:"nodelimit" bson:"nodelimit"`
|
||||
DefaultPostUp string `json:"defaultpostup" bson:"defaultpostup"`
|
||||
DefaultPostDown string `json:"defaultpostdown" bson:"defaultpostdown"`
|
||||
KeyUpdateTimeStamp int64 `json:"keyupdatetimestamp" bson:"keyupdatetimestamp"`
|
||||
DefaultKeepalive int32 `json:"defaultkeepalive" bson:"defaultkeepalive" validate:"omitempty,max=1000"`
|
||||
DefaultSaveConfig string `json:"defaultsaveconfig" bson:"defaultsaveconfig" validate:"checkyesorno"`
|
||||
AccessKeys []AccessKey `json:"accesskeys" bson:"accesskeys"`
|
||||
AllowManualSignUp string `json:"allowmanualsignup" bson:"allowmanualsignup" validate:"checkyesorno"`
|
||||
IsLocal string `json:"islocal" bson:"islocal" validate:"checkyesorno"`
|
||||
IsDualStack string `json:"isdualstack" bson:"isdualstack" validate:"checkyesorno"`
|
||||
IsIPv4 string `json:"isipv4" bson:"isipv4" validate:"checkyesorno"`
|
||||
IsIPv6 string `json:"isipv6" bson:"isipv6" validate:"checkyesorno"`
|
||||
IsGRPCHub string `json:"isgrpchub" bson:"isgrpchub" validate:"checkyesorno"`
|
||||
IsPointToSite string `json:"ispointtosite" bson:"ispointtosite" validate:"checkyesorno"`
|
||||
IsComms string `json:"iscomms" bson:"iscomms" validate:"checkyesorno"`
|
||||
LocalRange string `json:"localrange" bson:"localrange" validate:"omitempty,cidr"`
|
||||
|
||||
// checkin interval is depreciated at the network level. Set on server with CHECKIN_INTERVAL
|
||||
DefaultCheckInInterval int32 `json:"checkininterval,omitempty" bson:"checkininterval,omitempty" validate:"omitempty,numeric,min=2,max=100000"`
|
||||
DefaultUDPHolePunch string `json:"defaultudpholepunch" bson:"defaultudpholepunch" validate:"checkyesorno"`
|
||||
DefaultExtClientDNS string `json:"defaultextclientdns" bson:"defaultextclientdns"`
|
||||
DefaultMTU int32 `json:"defaultmtu" bson:"defaultmtu"`
|
||||
DefaultServerAddrs []ServerAddr `json:"defaultserveraddrs" bson:"defaultserveraddrs" yaml:"defaultserveraddrs"`
|
||||
DefaultUDPHolePunch string `json:"defaultudpholepunch" bson:"defaultudpholepunch" validate:"checkyesorno"`
|
||||
DefaultExtClientDNS string `json:"defaultextclientdns" bson:"defaultextclientdns"`
|
||||
DefaultMTU int32 `json:"defaultmtu" bson:"defaultmtu"`
|
||||
// consider removing - may be depreciated
|
||||
DefaultServerAddrs []ServerAddr `json:"defaultserveraddrs" bson:"defaultserveraddrs" yaml:"defaultserveraddrs"`
|
||||
}
|
||||
|
||||
// SaveData - sensitive fields of a network that should be kept the same
|
||||
|
@ -46,19 +39,6 @@ type SaveData struct { // put sensitive fields here
|
|||
NetID string `json:"netid" bson:"netid" validate:"required,min=1,max=12,netid_valid"`
|
||||
}
|
||||
|
||||
// Network.DisplayNameInNetworkCharSet - checks if displayname uses valid characters
|
||||
func (network *Network) DisplayNameInNetworkCharSet() bool {
|
||||
|
||||
charset := "abcdefghijklmnopqrstuvwxyz1234567890-_./;% ^#()!@$*"
|
||||
|
||||
for _, char := range network.DisplayName {
|
||||
if !strings.Contains(charset, strings.ToLower(string(char))) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Network.SetNodesLastModified - sets nodes last modified on network, depricated
|
||||
func (network *Network) SetNodesLastModified() {
|
||||
network.NodesLastModified = time.Now().Unix()
|
||||
|
@ -72,20 +52,16 @@ func (network *Network) SetNetworkLastModified() {
|
|||
// Network.SetDefaults - sets default values for a network struct
|
||||
func (network *Network) SetDefaults() {
|
||||
if network.DefaultUDPHolePunch == "" {
|
||||
if servercfg.IsClientMode() != "off" {
|
||||
network.DefaultUDPHolePunch = "yes"
|
||||
} else {
|
||||
network.DefaultUDPHolePunch = "no"
|
||||
}
|
||||
network.DefaultUDPHolePunch = "no"
|
||||
}
|
||||
if network.IsLocal == "" {
|
||||
network.IsLocal = "no"
|
||||
}
|
||||
if network.IsGRPCHub == "" {
|
||||
network.IsGRPCHub = "no"
|
||||
if network.IsPointToSite == "" {
|
||||
network.IsPointToSite = "no"
|
||||
}
|
||||
if network.DisplayName == "" {
|
||||
network.DisplayName = network.NetID
|
||||
if network.IsComms == "" {
|
||||
network.IsComms = "no"
|
||||
}
|
||||
if network.DefaultInterface == "" {
|
||||
if len(network.NetID) < 13 {
|
||||
|
@ -100,16 +76,9 @@ func (network *Network) SetDefaults() {
|
|||
if network.NodeLimit == 0 {
|
||||
network.NodeLimit = 999999999
|
||||
}
|
||||
if network.DefaultSaveConfig == "" {
|
||||
network.DefaultSaveConfig = "no"
|
||||
}
|
||||
if network.DefaultKeepalive == 0 {
|
||||
network.DefaultKeepalive = 20
|
||||
}
|
||||
//Check-In Interval for Nodes, In Seconds
|
||||
if network.DefaultCheckInInterval == 0 {
|
||||
network.DefaultCheckInInterval = 30
|
||||
}
|
||||
if network.AllowManualSignUp == "" {
|
||||
network.AllowManualSignUp = "no"
|
||||
}
|
||||
|
|
142
models/node.go
142
models/node.go
|
@ -10,15 +10,23 @@ import (
|
|||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
const TEN_YEARS_IN_SECONDS = 300000000
|
||||
const MAX_NAME_LENGTH = 62
|
||||
|
||||
// == ACTIONS == (can only be set by GRPC)
|
||||
const NODE_UPDATE_KEY = "updatekey"
|
||||
const NODE_SERVER_NAME = "netmaker"
|
||||
const NODE_DELETE = "delete"
|
||||
const NODE_IS_PENDING = "pending"
|
||||
const NODE_NOOP = "noop"
|
||||
const (
|
||||
// NODE_SERVER_NAME - the default server name
|
||||
NODE_SERVER_NAME = "netmaker"
|
||||
// TEN_YEARS_IN_SECONDS - ten years in seconds
|
||||
TEN_YEARS_IN_SECONDS = 300000000
|
||||
// MAX_NAME_LENGTH - max name length of node
|
||||
MAX_NAME_LENGTH = 62
|
||||
// == ACTIONS == (can only be set by GRPC)
|
||||
// NODE_UPDATE_KEY - action to update key
|
||||
NODE_UPDATE_KEY = "updatekey"
|
||||
// NODE_DELETE - delete node action
|
||||
NODE_DELETE = "delete"
|
||||
// NODE_IS_PENDING - node pending status
|
||||
NODE_IS_PENDING = "pending"
|
||||
// NODE_NOOP - node no op action
|
||||
NODE_NOOP = "noop"
|
||||
)
|
||||
|
||||
var seededRand *rand.Rand = rand.New(
|
||||
rand.NewSource(time.Now().UnixNano()))
|
||||
|
@ -38,45 +46,41 @@ type Node struct {
|
|||
PostDown string `json:"postdown" bson:"postdown" yaml:"postdown"`
|
||||
AllowedIPs []string `json:"allowedips" bson:"allowedips" yaml:"allowedips"`
|
||||
PersistentKeepalive int32 `json:"persistentkeepalive" bson:"persistentkeepalive" yaml:"persistentkeepalive" validate:"omitempty,numeric,max=1000"`
|
||||
SaveConfig string `json:"saveconfig" bson:"saveconfig" yaml:"saveconfig" validate:"checkyesorno"`
|
||||
IsHub string `json:"ishub" bson:"ishub" yaml:"ishub" validate:"checkyesorno"`
|
||||
AccessKey string `json:"accesskey" bson:"accesskey" yaml:"accesskey"`
|
||||
Interface string `json:"interface" bson:"interface" yaml:"interface"`
|
||||
LastModified int64 `json:"lastmodified" bson:"lastmodified" yaml:"lastmodified"`
|
||||
KeyUpdateTimeStamp int64 `json:"keyupdatetimestamp" bson:"keyupdatetimestamp" yaml:"keyupdatetimestamp"`
|
||||
ExpirationDateTime int64 `json:"expdatetime" bson:"expdatetime" yaml:"expdatetime"`
|
||||
LastPeerUpdate int64 `json:"lastpeerupdate" bson:"lastpeerupdate" yaml:"lastpeerupdate"`
|
||||
LastCheckIn int64 `json:"lastcheckin" bson:"lastcheckin" yaml:"lastcheckin"`
|
||||
MacAddress string `json:"macaddress" bson:"macaddress" yaml:"macaddress" validate:"macaddress_unique"`
|
||||
// checkin interval is depreciated at the network level. Set on server with CHECKIN_INTERVAL
|
||||
CheckInInterval int32 `json:"checkininterval" bson:"checkininterval" yaml:"checkininterval"`
|
||||
Password string `json:"password" bson:"password" yaml:"password" validate:"required,min=6"`
|
||||
Network string `json:"network" bson:"network" yaml:"network" validate:"network_exists"`
|
||||
IsRelayed string `json:"isrelayed" bson:"isrelayed" yaml:"isrelayed"`
|
||||
IsPending string `json:"ispending" bson:"ispending" yaml:"ispending"`
|
||||
IsRelay string `json:"isrelay" bson:"isrelay" yaml:"isrelay" validate:"checkyesorno"`
|
||||
IsDocker string `json:"isdocker" bson:"isdocker" yaml:"isdocker" validate:"checkyesorno"`
|
||||
IsK8S string `json:"isk8s" bson:"isk8s" yaml:"isk8s" validate:"checkyesorno"`
|
||||
IsEgressGateway string `json:"isegressgateway" bson:"isegressgateway" yaml:"isegressgateway"`
|
||||
IsIngressGateway string `json:"isingressgateway" bson:"isingressgateway" yaml:"isingressgateway"`
|
||||
EgressGatewayRanges []string `json:"egressgatewayranges" bson:"egressgatewayranges" yaml:"egressgatewayranges"`
|
||||
RelayAddrs []string `json:"relayaddrs" bson:"relayaddrs" yaml:"relayaddrs"`
|
||||
IngressGatewayRange string `json:"ingressgatewayrange" bson:"ingressgatewayrange" yaml:"ingressgatewayrange"`
|
||||
IsStatic string `json:"isstatic" bson:"isstatic" yaml:"isstatic" validate:"checkyesorno"`
|
||||
UDPHolePunch string `json:"udpholepunch" bson:"udpholepunch" yaml:"udpholepunch" validate:"checkyesorno"`
|
||||
PullChanges string `json:"pullchanges" bson:"pullchanges" yaml:"pullchanges" validate:"checkyesorno"`
|
||||
DNSOn string `json:"dnson" bson:"dnson" yaml:"dnson" validate:"checkyesorno"`
|
||||
IsDualStack string `json:"isdualstack" bson:"isdualstack" yaml:"isdualstack" validate:"checkyesorno"`
|
||||
IsServer string `json:"isserver" bson:"isserver" yaml:"isserver" validate:"checkyesorno"`
|
||||
Action string `json:"action" bson:"action" yaml:"action"`
|
||||
IsLocal string `json:"islocal" bson:"islocal" yaml:"islocal" validate:"checkyesorno"`
|
||||
LocalRange string `json:"localrange" bson:"localrange" yaml:"localrange"`
|
||||
Roaming string `json:"roaming" bson:"roaming" yaml:"roaming" validate:"checkyesorno"`
|
||||
IPForwarding string `json:"ipforwarding" bson:"ipforwarding" yaml:"ipforwarding" validate:"checkyesorno"`
|
||||
OS string `json:"os" bson:"os" yaml:"os"`
|
||||
MTU int32 `json:"mtu" bson:"mtu" yaml:"mtu"`
|
||||
Version string `json:"version" bson:"version" yaml:"version"`
|
||||
ExcludedAddrs []string `json:"excludedaddrs" bson:"excludedaddrs" yaml:"excludedaddrs"`
|
||||
TrafficKeys TrafficKeys `json:"traffickeys" bson:"traffickeys" yaml:"traffickeys"`
|
||||
Password string `json:"password" bson:"password" yaml:"password" validate:"required,min=6"`
|
||||
Network string `json:"network" bson:"network" yaml:"network" validate:"network_exists"`
|
||||
IsRelayed string `json:"isrelayed" bson:"isrelayed" yaml:"isrelayed"`
|
||||
IsPending string `json:"ispending" bson:"ispending" yaml:"ispending"`
|
||||
IsRelay string `json:"isrelay" bson:"isrelay" yaml:"isrelay" validate:"checkyesorno"`
|
||||
IsDocker string `json:"isdocker" bson:"isdocker" yaml:"isdocker" validate:"checkyesorno"`
|
||||
IsK8S string `json:"isk8s" bson:"isk8s" yaml:"isk8s" validate:"checkyesorno"`
|
||||
IsEgressGateway string `json:"isegressgateway" bson:"isegressgateway" yaml:"isegressgateway"`
|
||||
IsIngressGateway string `json:"isingressgateway" bson:"isingressgateway" yaml:"isingressgateway"`
|
||||
EgressGatewayRanges []string `json:"egressgatewayranges" bson:"egressgatewayranges" yaml:"egressgatewayranges"`
|
||||
RelayAddrs []string `json:"relayaddrs" bson:"relayaddrs" yaml:"relayaddrs"`
|
||||
IngressGatewayRange string `json:"ingressgatewayrange" bson:"ingressgatewayrange" yaml:"ingressgatewayrange"`
|
||||
IsStatic string `json:"isstatic" bson:"isstatic" yaml:"isstatic" validate:"checkyesorno"`
|
||||
UDPHolePunch string `json:"udpholepunch" bson:"udpholepunch" yaml:"udpholepunch" validate:"checkyesorno"`
|
||||
//PullChanges string `json:"pullchanges" bson:"pullchanges" yaml:"pullchanges" validate:"checkyesorno"`
|
||||
DNSOn string `json:"dnson" bson:"dnson" yaml:"dnson" validate:"checkyesorno"`
|
||||
IsDualStack string `json:"isdualstack" bson:"isdualstack" yaml:"isdualstack" validate:"checkyesorno"`
|
||||
IsServer string `json:"isserver" bson:"isserver" yaml:"isserver" validate:"checkyesorno"`
|
||||
Action string `json:"action" bson:"action" yaml:"action"`
|
||||
IsLocal string `json:"islocal" bson:"islocal" yaml:"islocal" validate:"checkyesorno"`
|
||||
LocalRange string `json:"localrange" bson:"localrange" yaml:"localrange"`
|
||||
IPForwarding string `json:"ipforwarding" bson:"ipforwarding" yaml:"ipforwarding" validate:"checkyesorno"`
|
||||
OS string `json:"os" bson:"os" yaml:"os"`
|
||||
MTU int32 `json:"mtu" bson:"mtu" yaml:"mtu"`
|
||||
Version string `json:"version" bson:"version" yaml:"version"`
|
||||
CommID string `json:"commid" bson:"commid" yaml:"comid"`
|
||||
TrafficKeys TrafficKeys `json:"traffickeys" bson:"traffickeys" yaml:"traffickeys"`
|
||||
}
|
||||
|
||||
// NodesArray - used for node sorting
|
||||
|
@ -118,6 +122,13 @@ func (node *Node) SetDefaultIsRelayed() {
|
|||
}
|
||||
}
|
||||
|
||||
// Node.SetDefaultIsRelayed - set default is relayed
|
||||
func (node *Node) SetDefaultIsHub() {
|
||||
if node.IsHub == "" {
|
||||
node.IsHub = "no"
|
||||
}
|
||||
}
|
||||
|
||||
// Node.SetDefaultIsRelay - set default isrelay
|
||||
func (node *Node) SetDefaultIsRelay() {
|
||||
if node.IsRelay == "" {
|
||||
|
@ -161,18 +172,11 @@ func (node *Node) SetDefaultAction() {
|
|||
}
|
||||
|
||||
// Node.SetRoamingDefault - sets default roaming status
|
||||
func (node *Node) SetRoamingDefault() {
|
||||
if node.Roaming == "" {
|
||||
node.Roaming = "yes"
|
||||
}
|
||||
}
|
||||
|
||||
// Node.SetPullChangesDefault - sets default pull changes status
|
||||
func (node *Node) SetPullChangesDefault() {
|
||||
if node.PullChanges == "" {
|
||||
node.PullChanges = "no"
|
||||
}
|
||||
}
|
||||
//func (node *Node) SetRoamingDefault() {
|
||||
// if node.Roaming == "" {
|
||||
// node.Roaming = "yes"
|
||||
// }
|
||||
//}
|
||||
|
||||
// Node.SetIPForwardingDefault - set ip forwarding default
|
||||
func (node *Node) SetIPForwardingDefault() {
|
||||
|
@ -245,13 +249,6 @@ func (node *Node) SetDefaultName() {
|
|||
}
|
||||
}
|
||||
|
||||
// Node.SetDefaultExcludedAddrs - sets ExcludedAddrs to empty array if nil
|
||||
func (node *Node) SetDefaultExcludedAddrs() {
|
||||
if node.ExcludedAddrs == nil {
|
||||
node.ExcludedAddrs = make([]string, 0)
|
||||
}
|
||||
}
|
||||
|
||||
// Node.Fill - fills other node data into calling node data if not set on calling node
|
||||
func (newNode *Node) Fill(currentNode *Node) {
|
||||
newNode.ID = currentNode.ID
|
||||
|
@ -273,8 +270,6 @@ func (newNode *Node) Fill(currentNode *Node) {
|
|||
}
|
||||
if newNode.PublicKey == "" && newNode.IsStatic != "yes" {
|
||||
newNode.PublicKey = currentNode.PublicKey
|
||||
} else {
|
||||
newNode.KeyUpdateTimeStamp = time.Now().Unix()
|
||||
}
|
||||
if newNode.Endpoint == "" && newNode.IsStatic != "yes" {
|
||||
newNode.Endpoint = currentNode.Endpoint
|
||||
|
@ -291,9 +286,6 @@ func (newNode *Node) Fill(currentNode *Node) {
|
|||
if newNode.PersistentKeepalive == 0 {
|
||||
newNode.PersistentKeepalive = currentNode.PersistentKeepalive
|
||||
}
|
||||
if newNode.SaveConfig == "" {
|
||||
newNode.SaveConfig = currentNode.SaveConfig
|
||||
}
|
||||
if newNode.AccessKey == "" {
|
||||
newNode.AccessKey = currentNode.AccessKey
|
||||
}
|
||||
|
@ -303,9 +295,6 @@ func (newNode *Node) Fill(currentNode *Node) {
|
|||
if newNode.LastModified == 0 {
|
||||
newNode.LastModified = currentNode.LastModified
|
||||
}
|
||||
if newNode.KeyUpdateTimeStamp == 0 {
|
||||
newNode.LastModified = currentNode.LastModified
|
||||
}
|
||||
if newNode.ExpirationDateTime == 0 {
|
||||
newNode.ExpirationDateTime = currentNode.ExpirationDateTime
|
||||
}
|
||||
|
@ -318,9 +307,6 @@ func (newNode *Node) Fill(currentNode *Node) {
|
|||
if newNode.MacAddress == "" {
|
||||
newNode.MacAddress = currentNode.MacAddress
|
||||
}
|
||||
if newNode.CheckInInterval == 0 {
|
||||
newNode.CheckInInterval = currentNode.CheckInInterval
|
||||
}
|
||||
if newNode.Password != "" {
|
||||
err := bcrypt.CompareHashAndPassword([]byte(newNode.Password), []byte(currentNode.Password))
|
||||
if err != nil && currentNode.Password != newNode.Password {
|
||||
|
@ -354,7 +340,7 @@ func (newNode *Node) Fill(currentNode *Node) {
|
|||
newNode.IsStatic = currentNode.IsStatic
|
||||
}
|
||||
if newNode.UDPHolePunch == "" {
|
||||
newNode.UDPHolePunch = currentNode.SaveConfig
|
||||
newNode.UDPHolePunch = currentNode.UDPHolePunch
|
||||
}
|
||||
if newNode.DNSOn == "" {
|
||||
newNode.DNSOn = currentNode.DNSOn
|
||||
|
@ -368,12 +354,9 @@ func (newNode *Node) Fill(currentNode *Node) {
|
|||
if newNode.IPForwarding == "" {
|
||||
newNode.IPForwarding = currentNode.IPForwarding
|
||||
}
|
||||
if newNode.PullChanges == "" {
|
||||
newNode.PullChanges = currentNode.PullChanges
|
||||
}
|
||||
if newNode.Roaming == "" {
|
||||
newNode.Roaming = currentNode.Roaming
|
||||
}
|
||||
//if newNode.Roaming == "" {
|
||||
//newNode.Roaming = currentNode.Roaming
|
||||
//}
|
||||
if newNode.Action == "" {
|
||||
newNode.Action = currentNode.Action
|
||||
}
|
||||
|
@ -407,9 +390,6 @@ func (newNode *Node) Fill(currentNode *Node) {
|
|||
if newNode.Version == "" {
|
||||
newNode.Version = currentNode.Version
|
||||
}
|
||||
if newNode.ExcludedAddrs == nil || len(newNode.ExcludedAddrs) != len(currentNode.ExcludedAddrs) {
|
||||
newNode.ExcludedAddrs = currentNode.ExcludedAddrs
|
||||
}
|
||||
}
|
||||
|
||||
// StringWithCharset - returns random string inside defined charset
|
||||
|
|
131
mq/handlers.go
Normal file
131
mq/handlers.go
Normal file
|
@ -0,0 +1,131 @@
|
|||
package mq
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
mqtt "github.com/eclipse/paho.mqtt.golang"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/netclient/ncutils"
|
||||
)
|
||||
|
||||
// DefaultHandler default message queue handler - only called when GetDebug == true
|
||||
func DefaultHandler(client mqtt.Client, msg mqtt.Message) {
|
||||
logger.Log(0, "MQTT Message: Topic: ", string(msg.Topic()), " Message: ", string(msg.Payload()))
|
||||
}
|
||||
|
||||
// Ping message Handler -- handles ping topic from client nodes
|
||||
func Ping(client mqtt.Client, msg mqtt.Message) {
|
||||
go func() {
|
||||
id, err := getID(msg.Topic())
|
||||
if err != nil {
|
||||
logger.Log(0, "error getting node.ID sent on ping topic ")
|
||||
return
|
||||
}
|
||||
node, err := logic.GetNodeByID(id)
|
||||
if err != nil {
|
||||
logger.Log(0, "mq-ping error getting node: ", err.Error())
|
||||
record, err := database.FetchRecord(database.NODES_TABLE_NAME, id)
|
||||
if err != nil {
|
||||
logger.Log(0, "error reading database ", err.Error())
|
||||
return
|
||||
}
|
||||
logger.Log(0, "record from database")
|
||||
logger.Log(0, record)
|
||||
return
|
||||
}
|
||||
_, decryptErr := decryptMsg(&node, msg.Payload())
|
||||
if decryptErr != nil {
|
||||
logger.Log(0, "error decrypting when updating node ", node.ID, decryptErr.Error())
|
||||
return
|
||||
}
|
||||
node.SetLastCheckIn()
|
||||
if err := logic.UpdateNode(&node, &node); err != nil {
|
||||
logger.Log(0, "error updating node", node.Name, node.ID, " on checkin", err.Error())
|
||||
return
|
||||
}
|
||||
logger.Log(3, "ping processed for node", node.ID)
|
||||
// --TODO --set client version once feature is implemented.
|
||||
//node.SetClientVersion(msg.Payload())
|
||||
}()
|
||||
}
|
||||
|
||||
// UpdateNode message Handler -- handles updates from client nodes
|
||||
func UpdateNode(client mqtt.Client, msg mqtt.Message) {
|
||||
go func() {
|
||||
id, err := getID(msg.Topic())
|
||||
if err != nil {
|
||||
logger.Log(1, "error getting node.ID sent on ", msg.Topic(), err.Error())
|
||||
return
|
||||
}
|
||||
currentNode, err := logic.GetNodeByID(id)
|
||||
if err != nil {
|
||||
logger.Log(1, "error getting node ", id, err.Error())
|
||||
return
|
||||
}
|
||||
decrypted, decryptErr := decryptMsg(¤tNode, msg.Payload())
|
||||
if decryptErr != nil {
|
||||
logger.Log(1, "failed to decrypt message for node ", id, decryptErr.Error())
|
||||
return
|
||||
}
|
||||
var newNode models.Node
|
||||
if err := json.Unmarshal(decrypted, &newNode); err != nil {
|
||||
logger.Log(1, "error unmarshaling payload ", err.Error())
|
||||
return
|
||||
}
|
||||
if err := logic.UpdateNode(¤tNode, &newNode); err != nil {
|
||||
logger.Log(1, "error saving node", err.Error())
|
||||
return
|
||||
}
|
||||
logger.Log(1, "updated node", id, newNode.Name)
|
||||
}()
|
||||
}
|
||||
|
||||
// ClientPeerUpdate message handler -- handles updating peers after signal from client nodes
|
||||
func ClientPeerUpdate(client mqtt.Client, msg mqtt.Message) {
|
||||
go func() {
|
||||
id, err := getID(msg.Topic())
|
||||
if err != nil {
|
||||
logger.Log(1, "error getting node.ID sent on ", msg.Topic(), err.Error())
|
||||
return
|
||||
}
|
||||
currentNode, err := logic.GetNodeByID(id)
|
||||
if err != nil {
|
||||
logger.Log(1, "error getting node ", id, err.Error())
|
||||
return
|
||||
}
|
||||
decrypted, decryptErr := decryptMsg(¤tNode, msg.Payload())
|
||||
if decryptErr != nil {
|
||||
logger.Log(1, "failed to decrypt message during client peer update for node ", id, decryptErr.Error())
|
||||
return
|
||||
}
|
||||
switch decrypted[0] {
|
||||
case ncutils.ACK:
|
||||
currentServerNode, err := logic.GetNetworkServerLocal(currentNode.Network)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err := logic.ServerUpdate(¤tServerNode, false); err != nil {
|
||||
logger.Log(1, "server node:", currentServerNode.ID, "failed update")
|
||||
return
|
||||
}
|
||||
case ncutils.DONE:
|
||||
currentServerNode, err := logic.GetNetworkServerLocal(currentNode.Network)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err := logic.ServerUpdate(¤tServerNode, false); err != nil {
|
||||
logger.Log(1, "server node:", currentServerNode.ID, "failed update")
|
||||
return
|
||||
}
|
||||
if err := PublishPeerUpdate(¤tNode); err != nil {
|
||||
logger.Log(1, "error publishing peer update ", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
logger.Log(1, "sent peer updates after signal received from", id, currentNode.Name)
|
||||
}()
|
||||
}
|
226
mq/mq.go
226
mq/mq.go
|
@ -2,18 +2,11 @@ package mq
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
mqtt "github.com/eclipse/paho.mqtt.golang"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/netclient/ncutils"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
)
|
||||
|
@ -25,170 +18,6 @@ const MQ_DISCONNECT = 250
|
|||
|
||||
var peer_force_send = 0
|
||||
|
||||
// DefaultHandler default message queue handler - only called when GetDebug == true
|
||||
func DefaultHandler(client mqtt.Client, msg mqtt.Message) {
|
||||
logger.Log(0, "MQTT Message: Topic: ", string(msg.Topic()), " Message: ", string(msg.Payload()))
|
||||
}
|
||||
|
||||
// Ping message Handler -- handles ping topic from client nodes
|
||||
func Ping(client mqtt.Client, msg mqtt.Message) {
|
||||
logger.Log(0, "Ping Handler: ", msg.Topic())
|
||||
go func() {
|
||||
id, err := GetID(msg.Topic())
|
||||
if err != nil {
|
||||
logger.Log(0, "error getting node.ID sent on ping topic ")
|
||||
return
|
||||
}
|
||||
node, err := logic.GetNodeByID(id)
|
||||
if err != nil {
|
||||
logger.Log(0, "mq-ping error getting node: ", err.Error())
|
||||
record, err := database.FetchRecord(database.NODES_TABLE_NAME, id)
|
||||
if err != nil {
|
||||
logger.Log(0, "error reading database ", err.Error())
|
||||
return
|
||||
}
|
||||
logger.Log(0, "record from database")
|
||||
logger.Log(0, record)
|
||||
return
|
||||
}
|
||||
_, decryptErr := decryptMsg(&node, msg.Payload())
|
||||
if decryptErr != nil {
|
||||
logger.Log(0, "error updating node ", node.ID, err.Error())
|
||||
return
|
||||
}
|
||||
node.SetLastCheckIn()
|
||||
if err := logic.UpdateNode(&node, &node); err != nil {
|
||||
logger.Log(0, "error updating node ", err.Error())
|
||||
}
|
||||
logger.Log(3, "ping processed for node", node.ID)
|
||||
// --TODO --set client version once feature is implemented.
|
||||
//node.SetClientVersion(msg.Payload())
|
||||
}()
|
||||
}
|
||||
|
||||
// UpdateNode message Handler -- handles updates from client nodes
|
||||
func UpdateNode(client mqtt.Client, msg mqtt.Message) {
|
||||
go func() {
|
||||
id, err := GetID(msg.Topic())
|
||||
if err != nil {
|
||||
logger.Log(1, "error getting node.ID sent on ", msg.Topic(), err.Error())
|
||||
return
|
||||
}
|
||||
currentNode, err := logic.GetNodeByID(id)
|
||||
if err != nil {
|
||||
logger.Log(1, "error getting node ", id, err.Error())
|
||||
return
|
||||
}
|
||||
decrypted, decryptErr := decryptMsg(¤tNode, msg.Payload())
|
||||
if decryptErr != nil {
|
||||
logger.Log(1, "failed to decrypt message for node ", id, decryptErr.Error())
|
||||
return
|
||||
}
|
||||
logger.Log(1, "Update Node Handler", id)
|
||||
var newNode models.Node
|
||||
if err := json.Unmarshal(decrypted, &newNode); err != nil {
|
||||
logger.Log(1, "error unmarshaling payload ", err.Error())
|
||||
return
|
||||
}
|
||||
if err := logic.UpdateNode(¤tNode, &newNode); err != nil {
|
||||
logger.Log(1, "error saving node", err.Error())
|
||||
}
|
||||
if err := PublishPeerUpdate(&newNode); err != nil {
|
||||
logger.Log(1, "error publishing peer update ", err.Error())
|
||||
return
|
||||
}
|
||||
logger.Log(1, "no need to update peers")
|
||||
}()
|
||||
}
|
||||
|
||||
// PublishPeerUpdate --- deterines and publishes a peer update to all the peers of a node
|
||||
func PublishPeerUpdate(newNode *models.Node) error {
|
||||
if !servercfg.IsMessageQueueBackend() {
|
||||
return nil
|
||||
}
|
||||
networkNodes, err := logic.GetNetworkNodes(newNode.Network)
|
||||
if err != nil {
|
||||
logger.Log(1, "err getting Network Nodes", err.Error())
|
||||
return err
|
||||
}
|
||||
for _, node := range networkNodes {
|
||||
|
||||
if node.IsServer == "yes" || node.ID == newNode.ID {
|
||||
continue
|
||||
}
|
||||
peerUpdate, err := logic.GetPeerUpdate(&node)
|
||||
if err != nil {
|
||||
logger.Log(1, "error getting peer update for node", node.ID, err.Error())
|
||||
continue
|
||||
}
|
||||
data, err := json.Marshal(&peerUpdate)
|
||||
if err != nil {
|
||||
logger.Log(2, "error marshaling peer update for node", node.ID, err.Error())
|
||||
continue
|
||||
}
|
||||
if err = publish(&node, fmt.Sprintf("peers/%s/%s", node.Network, node.ID), data); err != nil {
|
||||
logger.Log(1, "failed to publish peer update for node", node.ID)
|
||||
} else {
|
||||
logger.Log(1, fmt.Sprintf("sent peer update for node %s on network: %s ", node.Name, node.Network))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PublishPeerUpdate --- deterines and publishes a peer update to all the peers of a node
|
||||
func PublishExtPeerUpdate(node *models.Node) error {
|
||||
var err error
|
||||
if logic.IsLocalServer(node) {
|
||||
if err = logic.ServerUpdate(node, false); err != nil {
|
||||
logger.Log(1, "server node:", node.ID, "failed to update peers with ext clients")
|
||||
return err
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if !servercfg.IsMessageQueueBackend() {
|
||||
return nil
|
||||
}
|
||||
peerUpdate, err := logic.GetPeerUpdate(node)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := json.Marshal(&peerUpdate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return publish(node, fmt.Sprintf("peers/%s/%s", node.Network, node.ID), data)
|
||||
}
|
||||
|
||||
// GetID -- decodes a message queue topic and returns the embedded node.ID
|
||||
func GetID(topic string) (string, error) {
|
||||
parts := strings.Split(topic, "/")
|
||||
count := len(parts)
|
||||
if count == 1 {
|
||||
return "", errors.New("invalid topic")
|
||||
}
|
||||
//the last part of the topic will be the node.ID
|
||||
return parts[count-1], nil
|
||||
}
|
||||
|
||||
// NodeUpdate -- publishes a node update
|
||||
func NodeUpdate(node *models.Node) error {
|
||||
if !servercfg.IsMessageQueueBackend() {
|
||||
return nil
|
||||
}
|
||||
logger.Log(3, "publishing node update to "+node.Name)
|
||||
data, err := json.Marshal(node)
|
||||
if err != nil {
|
||||
logger.Log(2, "error marshalling node update ", err.Error())
|
||||
return err
|
||||
}
|
||||
if err = publish(node, fmt.Sprintf("update/%s/%s", node.Network, node.ID), data); err != nil {
|
||||
logger.Log(2, "error publishing node update to peer ", node.ID, err.Error())
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetupMQTT creates a connection to broker and return client
|
||||
func SetupMQTT(publish bool) mqtt.Client {
|
||||
opts := mqtt.NewClientOptions()
|
||||
|
@ -216,6 +45,10 @@ func SetupMQTT(publish bool) mqtt.Client {
|
|||
client.Disconnect(240)
|
||||
logger.Log(0, "node update subscription failed")
|
||||
}
|
||||
if token := client.Subscribe("signal/#", 0, mqtt.MessageHandler(ClientPeerUpdate)); token.Wait() && token.Error() != nil {
|
||||
client.Disconnect(240)
|
||||
logger.Log(0, "node client subscription failed")
|
||||
}
|
||||
|
||||
opts.SetOrderMatters(true)
|
||||
opts.SetResumeSubs(true)
|
||||
|
@ -248,54 +81,3 @@ func Keepalive(ctx context.Context) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sendPeers - retrieve networks, send peer ports to all peers
|
||||
func sendPeers() {
|
||||
var force bool
|
||||
peer_force_send++
|
||||
if peer_force_send == 5 {
|
||||
force = true
|
||||
peer_force_send = 0
|
||||
}
|
||||
networks, err := logic.GetNetworks()
|
||||
if err != nil {
|
||||
logger.Log(1, "error retrieving networks for keepalive", err.Error())
|
||||
}
|
||||
for _, network := range networks {
|
||||
serverNode, errN := logic.GetNetworkServerLeader(network.NetID)
|
||||
if errN == nil {
|
||||
serverNode.SetLastCheckIn()
|
||||
logic.UpdateNode(&serverNode, &serverNode)
|
||||
if network.DefaultUDPHolePunch == "yes" {
|
||||
if logic.ShouldPublishPeerPorts(&serverNode) || force {
|
||||
if force {
|
||||
logger.Log(2, "sending scheduled peer update (5 min)")
|
||||
}
|
||||
err = PublishPeerUpdate(&serverNode)
|
||||
if err != nil {
|
||||
logger.Log(1, "error publishing udp port updates for network", network.NetID)
|
||||
logger.Log(1, errN.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.Log(1, "unable to retrieve leader for network ", network.NetID)
|
||||
logger.Log(1, errN.Error())
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// func publishServerKeepalive(client mqtt.Client, network *models.Network) {
|
||||
// nodes, err := logic.GetNetworkNodes(network.NetID)
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
// for _, node := range nodes {
|
||||
// if token := client.Publish(fmt.Sprintf("serverkeepalive/%s/%s", network.NetID, node.ID), 0, false, servercfg.GetVersion()); token.Wait() && token.Error() != nil {
|
||||
// logger.Log(1, "error publishing server keepalive for network", network.NetID, token.Error().Error())
|
||||
// } else {
|
||||
// logger.Log(2, "keepalive sent for network/node", network.NetID, node.ID)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
|
127
mq/publishers.go
Normal file
127
mq/publishers.go
Normal file
|
@ -0,0 +1,127 @@
|
|||
package mq
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
)
|
||||
|
||||
// PublishPeerUpdate --- deterines and publishes a peer update to all the peers of a node
|
||||
func PublishPeerUpdate(newNode *models.Node) error {
|
||||
if !servercfg.IsMessageQueueBackend() {
|
||||
return nil
|
||||
}
|
||||
networkNodes, err := logic.GetNetworkNodes(newNode.Network)
|
||||
if err != nil {
|
||||
logger.Log(1, "err getting Network Nodes", err.Error())
|
||||
return err
|
||||
}
|
||||
for _, node := range networkNodes {
|
||||
|
||||
if node.IsServer == "yes" || node.ID == newNode.ID {
|
||||
continue
|
||||
}
|
||||
peerUpdate, err := logic.GetPeerUpdate(&node)
|
||||
if err != nil {
|
||||
logger.Log(1, "error getting peer update for node", node.ID, err.Error())
|
||||
continue
|
||||
}
|
||||
data, err := json.Marshal(&peerUpdate)
|
||||
if err != nil {
|
||||
logger.Log(2, "error marshaling peer update for node", node.ID, err.Error())
|
||||
continue
|
||||
}
|
||||
if err = publish(&node, fmt.Sprintf("peers/%s/%s", node.Network, node.ID), data); err != nil {
|
||||
logger.Log(1, "failed to publish peer update for node", node.ID)
|
||||
} else {
|
||||
if node.Network != servercfg.GetCommsID() {
|
||||
logger.Log(1, "sent peer update for node", node.Name, "on network:", node.Network)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PublishPeerUpdate --- publishes a peer update to all the peers of a node
|
||||
func PublishExtPeerUpdate(node *models.Node) error {
|
||||
var err error
|
||||
if logic.IsLocalServer(node) {
|
||||
if err = logic.ServerUpdate(node, false); err != nil {
|
||||
logger.Log(1, "server node:", node.ID, "failed to update peers with ext clients")
|
||||
return err
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if !servercfg.IsMessageQueueBackend() {
|
||||
return nil
|
||||
}
|
||||
peerUpdate, err := logic.GetPeerUpdate(node)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := json.Marshal(&peerUpdate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return publish(node, fmt.Sprintf("peers/%s/%s", node.Network, node.ID), data)
|
||||
}
|
||||
|
||||
// NodeUpdate -- publishes a node update
|
||||
func NodeUpdate(node *models.Node) error {
|
||||
if !servercfg.IsMessageQueueBackend() || node.IsServer == "yes" {
|
||||
return nil
|
||||
}
|
||||
logger.Log(3, "publishing node update to "+node.Name)
|
||||
data, err := json.Marshal(node)
|
||||
if err != nil {
|
||||
logger.Log(2, "error marshalling node update ", err.Error())
|
||||
return err
|
||||
}
|
||||
if err = publish(node, fmt.Sprintf("update/%s/%s", node.Network, node.ID), data); err != nil {
|
||||
logger.Log(2, "error publishing node update to peer ", node.ID, err.Error())
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// sendPeers - retrieve networks, send peer ports to all peers
|
||||
func sendPeers() {
|
||||
var force bool
|
||||
peer_force_send++
|
||||
if peer_force_send == 5 {
|
||||
force = true
|
||||
peer_force_send = 0
|
||||
}
|
||||
networks, err := logic.GetNetworks()
|
||||
if err != nil {
|
||||
logger.Log(1, "error retrieving networks for keepalive", err.Error())
|
||||
}
|
||||
for _, network := range networks {
|
||||
serverNode, errN := logic.GetNetworkServerLeader(network.NetID)
|
||||
if errN == nil {
|
||||
serverNode.SetLastCheckIn()
|
||||
logic.UpdateNode(&serverNode, &serverNode)
|
||||
if network.DefaultUDPHolePunch == "yes" {
|
||||
if logic.ShouldPublishPeerPorts(&serverNode) || force {
|
||||
if force {
|
||||
logger.Log(2, "sending scheduled peer update (5 min)")
|
||||
}
|
||||
err = PublishPeerUpdate(&serverNode)
|
||||
if err != nil {
|
||||
logger.Log(1, "error publishing udp port updates for network", network.NetID)
|
||||
logger.Log(1, errN.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.Log(1, "unable to retrieve leader for network ", network.NetID)
|
||||
logger.Log(1, errN.Error())
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
26
mq/util.go
26
mq/util.go
|
@ -2,6 +2,7 @@ package mq
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
|
@ -10,7 +11,7 @@ import (
|
|||
|
||||
func decryptMsg(node *models.Node, msg []byte) ([]byte, error) {
|
||||
if len(msg) <= 24 { // make sure message is of appropriate length
|
||||
return nil, fmt.Errorf("recieved invalid message from broker %s", string(msg))
|
||||
return nil, fmt.Errorf("recieved invalid message from broker %v", msg)
|
||||
}
|
||||
|
||||
trafficKey, trafficErr := logic.RetrievePrivateTrafficKey() // get server private key
|
||||
|
@ -26,7 +27,11 @@ func decryptMsg(node *models.Node, msg []byte) ([]byte, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return ncutils.BoxDecrypt(msg, nodePubTKey, serverPrivTKey)
|
||||
if strings.Contains(node.Version, "0.10.0") {
|
||||
return ncutils.BoxDecrypt(msg, nodePubTKey, serverPrivTKey)
|
||||
}
|
||||
|
||||
return ncutils.DeChunk(msg, nodePubTKey, serverPrivTKey)
|
||||
}
|
||||
|
||||
func encryptMsg(node *models.Node, msg []byte) ([]byte, error) {
|
||||
|
@ -46,7 +51,11 @@ func encryptMsg(node *models.Node, msg []byte) ([]byte, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return ncutils.BoxEncrypt(msg, nodePubKey, serverPrivKey)
|
||||
if strings.Contains(node.Version, "0.10.0") {
|
||||
return ncutils.BoxEncrypt(msg, nodePubKey, serverPrivKey)
|
||||
}
|
||||
|
||||
return ncutils.Chunk(msg, nodePubKey, serverPrivKey)
|
||||
}
|
||||
|
||||
func publish(node *models.Node, dest string, msg []byte) error {
|
||||
|
@ -61,3 +70,14 @@ func publish(node *models.Node, dest string, msg []byte) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// decodes a message queue topic and returns the embedded node.ID
|
||||
func getID(topic string) (string, error) {
|
||||
parts := strings.Split(topic, "/")
|
||||
count := len(parts)
|
||||
if count == 1 {
|
||||
return "", fmt.Errorf("invalid topic")
|
||||
}
|
||||
//the last part of the topic will be the node.ID
|
||||
return parts[count-1], nil
|
||||
}
|
||||
|
|
|
@ -43,40 +43,10 @@ func GetCommands(cliFlags []cli.Flag) []*cli.Command {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = command.Leave(cfg)
|
||||
err = command.Leave(cfg, c.String("force") == "yes")
|
||||
return err
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "checkin",
|
||||
Usage: "Checks for local changes and then checks into the specified Netmaker network to ask about remote changes.",
|
||||
Flags: cliFlags,
|
||||
// the action, or code that will be executed when
|
||||
// we execute our `ns` command
|
||||
Action: func(c *cli.Context) error {
|
||||
cfg, _, err := config.GetCLIConfig(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = command.CheckIn(cfg)
|
||||
return err
|
||||
},
|
||||
},
|
||||
// {
|
||||
// Name: "push",
|
||||
// Usage: "Push configuration changes to server.",
|
||||
// Flags: cliFlags,
|
||||
// // the action, or code that will be executed when
|
||||
// // we execute our `ns` command
|
||||
// Action: func(c *cli.Context) error {
|
||||
// cfg, _, err := config.GetCLIConfig(c)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// err = command.Push(cfg)
|
||||
// return err
|
||||
// },
|
||||
// },
|
||||
{
|
||||
Name: "pull",
|
||||
Usage: "Pull latest configuration and peers from server.",
|
||||
|
|
|
@ -198,5 +198,11 @@ func GetFlags(hostname string) []cli.Flag {
|
|||
Value: "yes",
|
||||
Usage: "Checks for IP changes if 'yes'. Ignores if 'no'. Yes by default.",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "force",
|
||||
EnvVars: []string{"NETCLIENT_FORCE"},
|
||||
Value: "no",
|
||||
Usage: "Allows to run the command with force, if otherwise prevented.",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gravitl/netmaker/netclient/config"
|
||||
"github.com/gravitl/netmaker/netclient/daemon"
|
||||
|
@ -12,15 +9,47 @@ import (
|
|||
"github.com/gravitl/netmaker/netclient/ncutils"
|
||||
)
|
||||
|
||||
// JoinComms -- Join the message queue comms network if it doesn't have it
|
||||
// tries to ping if already found locally, if fail ping pull for best effort for communication
|
||||
func JoinComms(cfg *config.ClientConfig) error {
|
||||
var commsCfg config.ClientConfig
|
||||
commsCfg.Network = cfg.Server.CommsNetwork
|
||||
commsCfg.Node.Network = cfg.Server.CommsNetwork
|
||||
commsCfg.Server.AccessKey = cfg.Server.AccessKey
|
||||
commsCfg.Server.GRPCAddress = cfg.Server.GRPCAddress
|
||||
commsCfg.Server.GRPCSSL = cfg.Server.GRPCSSL
|
||||
commsCfg.Server.CoreDNSAddr = cfg.Server.CoreDNSAddr
|
||||
if commsCfg.ConfigFileExists() {
|
||||
commsCfg.ReadConfig()
|
||||
}
|
||||
if commsCfg.Node.Name == "" {
|
||||
if err := functions.JoinNetwork(commsCfg, "", true); err != nil {
|
||||
return err
|
||||
}
|
||||
} else { // check if comms is currently reachable
|
||||
if err := functions.PingServer(&commsCfg); err != nil {
|
||||
if err = Pull(commsCfg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Join - join command to run from cli
|
||||
func Join(cfg config.ClientConfig, privateKey string) error {
|
||||
|
||||
var err error
|
||||
err = functions.JoinNetwork(cfg, privateKey)
|
||||
//check if comms network exists
|
||||
if err = JoinComms(&cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//join network
|
||||
err = functions.JoinNetwork(cfg, privateKey, false)
|
||||
if err != nil && !cfg.DebugOn {
|
||||
if !strings.Contains(err.Error(), "ALREADY_INSTALLED") {
|
||||
ncutils.PrintLog("error installing: "+err.Error(), 1)
|
||||
err = functions.LeaveNetwork(cfg.Network)
|
||||
err = functions.LeaveNetwork(cfg.Network, true)
|
||||
if err != nil {
|
||||
err = functions.WipeLocal(cfg.Network)
|
||||
if err != nil {
|
||||
|
@ -48,134 +77,30 @@ func Join(cfg config.ClientConfig, privateKey string) error {
|
|||
return err
|
||||
}
|
||||
ncutils.PrintLog("joined "+cfg.Network, 1)
|
||||
if ncutils.IsWindows() {
|
||||
ncutils.PrintLog("setting up WireGuard app", 0)
|
||||
time.Sleep(time.Second >> 1)
|
||||
functions.Pull(cfg.Network, true)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func getWindowsInterval() int {
|
||||
interval := 15
|
||||
networks, err := ncutils.GetSystemNetworks()
|
||||
if err != nil {
|
||||
return interval
|
||||
}
|
||||
cfg, err := config.ReadConfig(networks[0])
|
||||
if err != nil {
|
||||
return interval
|
||||
}
|
||||
netint, err := strconv.Atoi(cfg.Server.CheckinInterval)
|
||||
if err == nil && netint != 0 {
|
||||
interval = netint
|
||||
}
|
||||
return interval
|
||||
}
|
||||
|
||||
// RunUserspaceDaemon - runs continual checkins
|
||||
func RunUserspaceDaemon() {
|
||||
|
||||
cfg := config.ClientConfig{
|
||||
Network: "all",
|
||||
}
|
||||
interval := getWindowsInterval()
|
||||
dur := time.Duration(interval) * time.Second
|
||||
for {
|
||||
CheckIn(cfg)
|
||||
time.Sleep(dur)
|
||||
}
|
||||
}
|
||||
|
||||
// CheckIn - runs checkin command from cli
|
||||
func CheckIn(cfg config.ClientConfig) error {
|
||||
//log.Println("checkin --- diabled for now")
|
||||
//return nil
|
||||
var err error
|
||||
var errN 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 := ncutils.GetSystemNetworks()
|
||||
if err != nil {
|
||||
ncutils.PrintLog("error retrieving networks, exiting", 1)
|
||||
return err
|
||||
/*
|
||||
if ncutils.IsWindows() {
|
||||
ncutils.PrintLog("setting up WireGuard app", 0)
|
||||
time.Sleep(time.Second >> 1)
|
||||
functions.Pull(cfg.Network, true)
|
||||
}
|
||||
for _, network := range networks {
|
||||
currConf, err := config.ReadConfig(network)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
err = functions.CheckConfig(*currConf)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "could not find iface") {
|
||||
err = Pull(cfg)
|
||||
if err != nil {
|
||||
ncutils.PrintLog(err.Error(), 1)
|
||||
}
|
||||
} else {
|
||||
ncutils.PrintLog("error checking in for "+network+" network: "+err.Error(), 1)
|
||||
}
|
||||
} else {
|
||||
ncutils.PrintLog("checked in successfully for "+network, 1)
|
||||
}
|
||||
}
|
||||
if len(networks) == 0 {
|
||||
if ncutils.IsWindows() { // Windows specific - there are no netclients, so stop daemon process
|
||||
daemon.StopWindowsDaemon()
|
||||
}
|
||||
}
|
||||
errN = err
|
||||
err = nil
|
||||
} else {
|
||||
err = functions.CheckConfig(cfg)
|
||||
}
|
||||
if err == nil && errN != nil {
|
||||
err = errN
|
||||
}
|
||||
*/
|
||||
return err
|
||||
}
|
||||
|
||||
// Leave - runs the leave command from cli
|
||||
func Leave(cfg config.ClientConfig) error {
|
||||
err := functions.LeaveNetwork(cfg.Network)
|
||||
func Leave(cfg config.ClientConfig, force bool) error {
|
||||
err := functions.LeaveNetwork(cfg.Network, force)
|
||||
if err != nil {
|
||||
ncutils.PrintLog("error attempting to leave network "+cfg.Network, 1)
|
||||
} else {
|
||||
ncutils.PrintLog("success", 0)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Push - runs push command
|
||||
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 := ncutils.GetSystemNetworks()
|
||||
if err != nil {
|
||||
ncutils.PrintLog("error retrieving networks, exiting.", 0)
|
||||
return err
|
||||
nets, err := ncutils.GetSystemNetworks()
|
||||
if err == nil && len(nets) == 1 {
|
||||
if nets[0] == cfg.Node.CommID {
|
||||
ncutils.PrintLog("detected comms as remaining network, removing...", 1)
|
||||
err = functions.LeaveNetwork(nets[0], true)
|
||||
}
|
||||
for _, network := range networks {
|
||||
err = functions.Push(network)
|
||||
if err != nil {
|
||||
ncutils.PrintLog("error pushing network configs for network: "+network+"\n"+err.Error(), 1)
|
||||
} else {
|
||||
ncutils.PrintLog("pushed network config for "+network, 1)
|
||||
}
|
||||
}
|
||||
err = nil
|
||||
} else {
|
||||
err = functions.Push(cfg.Network)
|
||||
}
|
||||
if err == nil {
|
||||
ncutils.PrintLog("completed pushing network configs to remote server", 1)
|
||||
ncutils.PrintLog("success", 1)
|
||||
} else {
|
||||
ncutils.PrintLog("error occurred pushing configs", 1)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -226,6 +151,7 @@ func Uninstall() error {
|
|||
return err
|
||||
}
|
||||
|
||||
// Daemon - runs the daemon
|
||||
func Daemon() error {
|
||||
err := functions.Daemon()
|
||||
return err
|
||||
|
|
|
@ -15,12 +15,6 @@ import (
|
|||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// GlobalConfig - struct for handling IntClients currently
|
||||
type GlobalConfig struct {
|
||||
GRPCWireGuard string `yaml:"grpcwg"`
|
||||
Client models.IntClient
|
||||
}
|
||||
|
||||
// ClientConfig - struct for dealing with client configuration
|
||||
type ClientConfig struct {
|
||||
Server ServerConfig `yaml:"server"`
|
||||
|
@ -34,13 +28,11 @@ type ClientConfig struct {
|
|||
|
||||
// ServerConfig - struct for dealing with the server information for a netclient
|
||||
type ServerConfig struct {
|
||||
CoreDNSAddr string `yaml:"corednsaddr"`
|
||||
GRPCAddress string `yaml:"grpcaddress"`
|
||||
APIAddress string `yaml:"apiaddress"`
|
||||
AccessKey string `yaml:"accesskey"`
|
||||
GRPCSSL string `yaml:"grpcssl"`
|
||||
GRPCWireGuard string `yaml:"grpcwg"`
|
||||
CheckinInterval string `yaml:"checkininterval"`
|
||||
CoreDNSAddr string `yaml:"corednsaddr"`
|
||||
GRPCAddress string `yaml:"grpcaddress"`
|
||||
AccessKey string `yaml:"accesskey"`
|
||||
GRPCSSL string `yaml:"grpcssl"`
|
||||
CommsNetwork string `yaml:"commsnetwork"`
|
||||
}
|
||||
|
||||
// Write - writes the config of a client to disk
|
||||
|
@ -71,6 +63,18 @@ func Write(config *ClientConfig, network string) error {
|
|||
return f.Sync()
|
||||
}
|
||||
|
||||
// ConfigFileExists - return true if config file exists
|
||||
func (config *ClientConfig) ConfigFileExists() bool {
|
||||
home := ncutils.GetNetclientPathSpecific()
|
||||
|
||||
file := fmt.Sprintf(home + "netconfig-" + config.Network)
|
||||
info, err := os.Stat(file)
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
return !info.IsDir()
|
||||
}
|
||||
|
||||
// ClientConfig.ReadConfig - used to read config from client disk into memory
|
||||
func (config *ClientConfig) ReadConfig() {
|
||||
|
||||
|
@ -82,8 +86,7 @@ func (config *ClientConfig) ReadConfig() {
|
|||
//f, err := os.Open(file)
|
||||
f, err := os.OpenFile(file, os.O_RDONLY, 0600)
|
||||
if err != nil {
|
||||
fmt.Println("trouble opening file")
|
||||
fmt.Println(err)
|
||||
ncutils.PrintLog("trouble opening file: "+err.Error(), 1)
|
||||
nofile = true
|
||||
//fmt.Println("Could not access " + home + "/.netconfig, proceeding...")
|
||||
}
|
||||
|
@ -175,21 +178,8 @@ func GetCLIConfig(c *cli.Context) (ClientConfig, string, error) {
|
|||
return cfg, "", err
|
||||
}
|
||||
|
||||
if accesstoken.ServerConfig.APIConnString != "" {
|
||||
cfg.Server.APIAddress = accesstoken.ServerConfig.APIConnString
|
||||
} else {
|
||||
cfg.Server.APIAddress = accesstoken.ServerConfig.APIHost
|
||||
if accesstoken.ServerConfig.APIPort != "" {
|
||||
cfg.Server.APIAddress = cfg.Server.APIAddress + ":" + accesstoken.ServerConfig.APIPort
|
||||
}
|
||||
}
|
||||
if accesstoken.ServerConfig.GRPCConnString != "" {
|
||||
cfg.Server.GRPCAddress = accesstoken.ServerConfig.GRPCConnString
|
||||
} else {
|
||||
cfg.Server.GRPCAddress = accesstoken.ServerConfig.GRPCHost
|
||||
if accesstoken.ServerConfig.GRPCPort != "" {
|
||||
cfg.Server.GRPCAddress = cfg.Server.GRPCAddress + ":" + accesstoken.ServerConfig.GRPCPort
|
||||
}
|
||||
}
|
||||
|
||||
cfg.Network = accesstoken.ClientConfig.Network
|
||||
|
@ -197,15 +187,10 @@ func GetCLIConfig(c *cli.Context) (ClientConfig, string, error) {
|
|||
cfg.Server.AccessKey = accesstoken.ClientConfig.Key
|
||||
cfg.Node.LocalRange = accesstoken.ClientConfig.LocalRange
|
||||
cfg.Server.GRPCSSL = accesstoken.ServerConfig.GRPCSSL
|
||||
cfg.Server.CheckinInterval = accesstoken.ServerConfig.CheckinInterval
|
||||
cfg.Server.GRPCWireGuard = accesstoken.WG.GRPCWireGuard
|
||||
cfg.Server.CoreDNSAddr = accesstoken.ServerConfig.CoreDNSAddr
|
||||
cfg.Server.CommsNetwork = accesstoken.ServerConfig.CommsNetwork
|
||||
if c.String("grpcserver") != "" {
|
||||
cfg.Server.GRPCAddress = c.String("grpcserver")
|
||||
}
|
||||
if c.String("apiserver") != "" {
|
||||
cfg.Server.APIAddress = c.String("apiserver")
|
||||
}
|
||||
if c.String("key") != "" {
|
||||
cfg.Server.AccessKey = c.String("key")
|
||||
}
|
||||
|
@ -222,24 +207,15 @@ func GetCLIConfig(c *cli.Context) (ClientConfig, string, error) {
|
|||
if c.String("corednsaddr") != "" {
|
||||
cfg.Server.CoreDNSAddr = c.String("corednsaddr")
|
||||
}
|
||||
if c.String("grpcwg") != "" {
|
||||
cfg.Server.GRPCWireGuard = c.String("grpcwg")
|
||||
}
|
||||
if c.String("checkininterval") != "" {
|
||||
cfg.Server.CheckinInterval = c.String("checkininterval")
|
||||
}
|
||||
|
||||
} else {
|
||||
cfg.Server.GRPCAddress = c.String("grpcserver")
|
||||
cfg.Server.APIAddress = c.String("apiserver")
|
||||
cfg.Server.AccessKey = c.String("key")
|
||||
cfg.Network = c.String("network")
|
||||
cfg.Node.Network = c.String("network")
|
||||
cfg.Node.LocalRange = c.String("localrange")
|
||||
cfg.Server.GRPCWireGuard = c.String("grpcwg")
|
||||
cfg.Server.GRPCSSL = c.String("grpcssl")
|
||||
cfg.Server.CoreDNSAddr = c.String("corednsaddr")
|
||||
cfg.Server.CheckinInterval = c.String("checkininterval")
|
||||
}
|
||||
cfg.Node.Name = c.String("name")
|
||||
cfg.Node.Interface = c.String("interface")
|
||||
|
@ -248,7 +224,7 @@ func GetCLIConfig(c *cli.Context) (ClientConfig, string, error) {
|
|||
cfg.Node.LocalAddress = c.String("localaddress")
|
||||
cfg.Node.Address = c.String("address")
|
||||
cfg.Node.Address6 = c.String("addressIPV6")
|
||||
cfg.Node.Roaming = c.String("roaming")
|
||||
//cfg.Node.Roaming = c.String("roaming")
|
||||
cfg.Node.DNSOn = c.String("dnson")
|
||||
cfg.Node.IsLocal = c.String("islocal")
|
||||
cfg.Node.IsStatic = c.String("isstatic")
|
||||
|
@ -266,10 +242,6 @@ func GetCLIConfig(c *cli.Context) (ClientConfig, string, error) {
|
|||
cfg.Node.UDPHolePunch = c.String("udpholepunch")
|
||||
cfg.Node.MTU = int32(c.Int("mtu"))
|
||||
|
||||
if cfg.Server.CheckinInterval == "" {
|
||||
cfg.Server.CheckinInterval = "15"
|
||||
}
|
||||
|
||||
return cfg, privateKey, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -13,18 +13,13 @@ func InstallDaemon(cfg config.ClientConfig) error {
|
|||
os := runtime.GOOS
|
||||
var err error
|
||||
|
||||
interval := "15"
|
||||
if cfg.Server.CheckinInterval != "" {
|
||||
interval = cfg.Server.CheckinInterval
|
||||
}
|
||||
|
||||
switch os {
|
||||
case "windows":
|
||||
err = SetupWindowsDaemon()
|
||||
case "darwin":
|
||||
err = SetupMacDaemon(interval)
|
||||
err = SetupMacDaemon()
|
||||
case "linux":
|
||||
err = SetupSystemDDaemon(interval)
|
||||
err = SetupSystemDDaemon()
|
||||
case "freebsd":
|
||||
err = SetupFreebsdDaemon()
|
||||
default:
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -14,7 +13,7 @@ const MAC_SERVICE_NAME = "com.gravitl.netclient"
|
|||
const MAC_EXEC_DIR = "/usr/local/bin/"
|
||||
|
||||
// SetupMacDaemon - Creates a daemon service from the netclient under LaunchAgents for MacOS
|
||||
func SetupMacDaemon(interval string) error {
|
||||
func SetupMacDaemon() error {
|
||||
|
||||
dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
|
||||
if err != nil {
|
||||
|
@ -34,7 +33,7 @@ func SetupMacDaemon(interval string) error {
|
|||
if os.IsNotExist(errN) {
|
||||
os.Mkdir("~/Library/LaunchAgents", 0755)
|
||||
}
|
||||
err = CreateMacService(MAC_SERVICE_NAME, interval)
|
||||
err = CreateMacService(MAC_SERVICE_NAME)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -69,7 +68,7 @@ func StopLaunchD() {
|
|||
}
|
||||
|
||||
// CreateMacService - Creates the mac service file for LaunchDaemons
|
||||
func CreateMacService(servicename string, interval string) error {
|
||||
func CreateMacService(servicename string) error {
|
||||
_, err := os.Stat("/Library/LaunchDaemons")
|
||||
if os.IsNotExist(err) {
|
||||
os.Mkdir("/Library/LaunchDaemons", 0755)
|
||||
|
@ -77,7 +76,7 @@ func CreateMacService(servicename string, interval string) error {
|
|||
log.Println("couldnt find or create /Library/LaunchDaemons")
|
||||
return err
|
||||
}
|
||||
daemonstring := MacDaemonString(interval)
|
||||
daemonstring := MacDaemonString()
|
||||
daemonbytes := []byte(daemonstring)
|
||||
|
||||
if !ncutils.FileExists("/Library/LaunchDaemons/com.gravitl.netclient.plist") {
|
||||
|
@ -87,8 +86,8 @@ func CreateMacService(servicename string, interval string) error {
|
|||
}
|
||||
|
||||
// MacDaemonString - the file contents for the mac netclient daemon service (launchdaemon)
|
||||
func MacDaemonString(interval string) string {
|
||||
return fmt.Sprintf(`<?xml version='1.0' encoding='UTF-8'?>
|
||||
func MacDaemonString() string {
|
||||
return `<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\" >
|
||||
<plist version='1.0'>
|
||||
<dict>
|
||||
|
@ -100,9 +99,11 @@ func MacDaemonString(interval string) string {
|
|||
</array>
|
||||
<key>StandardOutPath</key><string>/etc/netclient/com.gravitl.netclient.log</string>
|
||||
<key>StandardErrorPath</key><string>/etc/netclient/com.gravitl.netclient.log</string>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
<key>AbandonProcessGroup</key><true/>
|
||||
<key>StartInterval</key>
|
||||
<integer>%s</integer>
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>PATH</key>
|
||||
|
@ -110,7 +111,7 @@ func MacDaemonString(interval string) string {
|
|||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
`, interval)
|
||||
`
|
||||
}
|
||||
|
||||
// MacTemplateData - struct to represent the mac service
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
const EXEC_DIR = "/sbin/"
|
||||
|
||||
// SetupSystemDDaemon - sets system daemon for supported machines
|
||||
func SetupSystemDDaemon(interval string) error {
|
||||
func SetupSystemDDaemon() error {
|
||||
|
||||
if ncutils.IsWindows() {
|
||||
return nil
|
||||
|
|
|
@ -1,320 +0,0 @@
|
|||
package functions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
nodepb "github.com/gravitl/netmaker/grpc"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/netclient/auth"
|
||||
"github.com/gravitl/netmaker/netclient/config"
|
||||
"github.com/gravitl/netmaker/netclient/local"
|
||||
"github.com/gravitl/netmaker/netclient/ncutils"
|
||||
"github.com/gravitl/netmaker/netclient/wireguard"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/metadata"
|
||||
//homedir "github.com/mitchellh/go-homedir"
|
||||
)
|
||||
|
||||
func isDeleteError(err error) bool {
|
||||
return err != nil && strings.Contains(err.Error(), models.NODE_DELETE)
|
||||
}
|
||||
|
||||
func checkIP(node *models.Node, servercfg config.ServerConfig, cliconf config.ClientConfig, network string) bool {
|
||||
ipchange := false
|
||||
var err error
|
||||
if node.Roaming == "yes" && node.IsStatic != "yes" {
|
||||
if node.IsLocal == "no" {
|
||||
extIP, err := ncutils.GetPublicIP()
|
||||
if err != nil {
|
||||
ncutils.PrintLog("error encountered checking ip addresses: "+err.Error(), 1)
|
||||
}
|
||||
if node.Endpoint != extIP && extIP != "" {
|
||||
ncutils.PrintLog("endpoint has changed from "+
|
||||
node.Endpoint+" to "+extIP, 1)
|
||||
ncutils.PrintLog("updating address", 1)
|
||||
node.Endpoint = extIP
|
||||
ipchange = true
|
||||
}
|
||||
intIP, err := getPrivateAddr()
|
||||
if err != nil {
|
||||
ncutils.PrintLog("error encountered checking ip addresses: "+err.Error(), 1)
|
||||
}
|
||||
if node.LocalAddress != intIP && intIP != "" {
|
||||
ncutils.PrintLog("local Address has changed from "+
|
||||
node.LocalAddress+" to "+intIP, 1)
|
||||
ncutils.PrintLog("updating address", 1)
|
||||
node.LocalAddress = intIP
|
||||
ipchange = true
|
||||
}
|
||||
} else {
|
||||
localIP, err := ncutils.GetLocalIP(node.LocalRange)
|
||||
if err != nil {
|
||||
ncutils.PrintLog("error encountered checking ip addresses: "+err.Error(), 1)
|
||||
}
|
||||
if node.Endpoint != localIP && localIP != "" {
|
||||
ncutils.PrintLog("endpoint has changed from "+
|
||||
node.Endpoint+" to "+localIP, 1)
|
||||
ncutils.PrintLog("updating address", 1)
|
||||
node.Endpoint = localIP
|
||||
node.LocalAddress = localIP
|
||||
ipchange = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if ipchange {
|
||||
err = config.ModConfig(node)
|
||||
if err != nil {
|
||||
ncutils.PrintLog("error modifying config file: "+err.Error(), 1)
|
||||
return false
|
||||
}
|
||||
err = wireguard.SetWGConfig(network, false)
|
||||
if err != nil {
|
||||
ncutils.PrintLog("error setting wireguard config: "+err.Error(), 1)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return ipchange && err == nil
|
||||
}
|
||||
|
||||
// DEPRECATED
|
||||
// func setDNS(node *models.Node, servercfg config.ServerConfig, nodecfg *models.Node) {
|
||||
// if nodecfg.DNSOn == "yes" {
|
||||
// ifacename := node.Interface
|
||||
// nameserver := servercfg.CoreDNSAddr
|
||||
// network := node.Network
|
||||
// local.UpdateDNS(ifacename, network, nameserver)
|
||||
// }
|
||||
// }
|
||||
|
||||
func checkNodeActions(node *models.Node, networkName string, servercfg config.ServerConfig, localNode *models.Node, cfg *config.ClientConfig) string {
|
||||
if (node.Action == models.NODE_UPDATE_KEY || localNode.Action == models.NODE_UPDATE_KEY) &&
|
||||
node.IsStatic != "yes" {
|
||||
err := wireguard.SetWGKeyConfig(networkName, servercfg.GRPCAddress)
|
||||
if err != nil {
|
||||
ncutils.PrintLog("unable to process reset keys request: "+err.Error(), 1)
|
||||
return ""
|
||||
}
|
||||
}
|
||||
if node.Action == models.NODE_DELETE || localNode.Action == models.NODE_DELETE {
|
||||
err := RemoveLocalInstance(cfg, networkName)
|
||||
if err != nil {
|
||||
ncutils.PrintLog("error deleting locally: "+err.Error(), 1)
|
||||
}
|
||||
return models.NODE_DELETE
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// CheckConfig - checks if current config of client needs update, see flow below
|
||||
/**
|
||||
* Pull changes if any (interface refresh)
|
||||
* - Save it
|
||||
* Check local changes for (ipAddress, publickey, configfile changes) (interface refresh)
|
||||
* - Save it
|
||||
* - Push it
|
||||
* Pull Peers (sync)
|
||||
*/
|
||||
func CheckConfig(cliconf config.ClientConfig) error {
|
||||
|
||||
network := cliconf.Network
|
||||
cfg, err := config.ReadConfig(network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
servercfg := cfg.Server
|
||||
currentNode := cfg.Node
|
||||
|
||||
newNode, err := Pull(network, false)
|
||||
if isDeleteError(err) {
|
||||
return RemoveLocalInstance(cfg, network)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
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")
|
||||
}
|
||||
// Check if ip changed and push if so
|
||||
checkIP(newNode, servercfg, cliconf, network)
|
||||
return Push(network)
|
||||
}
|
||||
|
||||
// Pull - pulls the latest config from the server, if manual it will overwrite
|
||||
func Pull(network string, manual bool) (*models.Node, error) {
|
||||
cfg, err := config.ReadConfig(network)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
node := cfg.Node
|
||||
//servercfg := cfg.Server
|
||||
|
||||
if cfg.Node.IPForwarding == "yes" && !ncutils.IsWindows() {
|
||||
if err = local.SetIPForwarding(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
var resNode models.Node // just need to fill this with either server calls or client calls
|
||||
|
||||
var header metadata.MD
|
||||
var wcclient nodepb.NodeServiceClient
|
||||
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
|
||||
}
|
||||
data, err := json.Marshal(&node)
|
||||
if err != nil {
|
||||
ncutils.PrintLog("Failed to parse node config: "+err.Error(), 1)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := &nodepb.Object{
|
||||
Data: string(data),
|
||||
Type: nodepb.NODE_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
|
||||
}
|
||||
}
|
||||
// ensure that the OS never changes
|
||||
resNode.OS = runtime.GOOS
|
||||
if resNode.PullChanges == "yes" || manual {
|
||||
// check for interface change
|
||||
if cfg.Node.Interface != resNode.Interface {
|
||||
if err = DeleteInterface(cfg.Node.Interface, cfg.Node.PostDown); err != nil {
|
||||
ncutils.PrintLog("could not delete old interface "+cfg.Node.Interface, 1)
|
||||
}
|
||||
}
|
||||
resNode.PullChanges = "no"
|
||||
if err = config.ModConfig(&resNode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = wireguard.SetWGConfig(network, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nodeData, err := json.Marshal(&resNode)
|
||||
if err != nil {
|
||||
return &resNode, err
|
||||
}
|
||||
|
||||
if resNode.IsServer != "yes" {
|
||||
if wcclient == nil || ctx == nil {
|
||||
return &cfg.Node, errors.New("issue initializing gRPC client")
|
||||
}
|
||||
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 {
|
||||
if err = wireguard.SetWGConfig(network, true); err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) && !ncutils.IsFreeBSD() {
|
||||
return Pull(network, true)
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
var bkupErr = config.SaveBackup(network)
|
||||
if bkupErr != nil {
|
||||
ncutils.Log("unable to update backup file")
|
||||
}
|
||||
|
||||
return &resNode, err
|
||||
}
|
||||
|
||||
// Push - pushes current client configuration to server
|
||||
func Push(network string) error {
|
||||
|
||||
cfg, err := config.ReadConfig(network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
postnode := cfg.Node
|
||||
// always set the OS on client
|
||||
postnode.OS = runtime.GOOS
|
||||
postnode.SetLastCheckIn()
|
||||
|
||||
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
|
||||
}
|
||||
err = config.ModConfig(&postnode)
|
||||
return err
|
||||
}
|
|
@ -124,7 +124,7 @@ func Uninstall() error {
|
|||
ncutils.PrintLog("continuing uninstall without leaving networks", 1)
|
||||
} else {
|
||||
for _, network := range networks {
|
||||
err = LeaveNetwork(network)
|
||||
err = LeaveNetwork(network, true)
|
||||
if err != nil {
|
||||
ncutils.PrintLog("Encounter issue leaving network "+network+": "+err.Error(), 1)
|
||||
}
|
||||
|
@ -147,13 +147,16 @@ func Uninstall() error {
|
|||
}
|
||||
|
||||
// LeaveNetwork - client exits a network
|
||||
func LeaveNetwork(network string) error {
|
||||
func LeaveNetwork(network string, force bool) error {
|
||||
cfg, err := config.ReadConfig(network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
servercfg := cfg.Server
|
||||
node := cfg.Node
|
||||
if node.NetworkSettings.IsComms == "yes" && !force {
|
||||
return errors.New("COMMS_NET - You are trying to leave the comms network. This will break network updates. Unless you re-join. If you really want to leave, run with --force=yes.")
|
||||
}
|
||||
|
||||
if node.IsServer != "yes" {
|
||||
var wcclient nodepb.NodeServiceClient
|
||||
|
@ -317,58 +320,3 @@ func WipeLocal(network string) error {
|
|||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func getLocalIP(node models.Node) string {
|
||||
|
||||
var local string
|
||||
|
||||
ifaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return local
|
||||
}
|
||||
_, localrange, err := net.ParseCIDR(node.LocalRange)
|
||||
if err != nil {
|
||||
return local
|
||||
}
|
||||
|
||||
found := false
|
||||
for _, i := range ifaces {
|
||||
if i.Flags&net.FlagUp == 0 {
|
||||
continue // interface down
|
||||
}
|
||||
if i.Flags&net.FlagLoopback != 0 {
|
||||
continue // loopback interface
|
||||
}
|
||||
addrs, err := i.Addrs()
|
||||
if err != nil {
|
||||
return local
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
var ip net.IP
|
||||
switch v := addr.(type) {
|
||||
case *net.IPNet:
|
||||
if !found {
|
||||
ip = v.IP
|
||||
local = ip.String()
|
||||
if node.IsLocal == "yes" {
|
||||
found = localrange.Contains(ip)
|
||||
} else {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
case *net.IPAddr:
|
||||
if !found {
|
||||
ip = v.IP
|
||||
local = ip.String()
|
||||
if node.IsLocal == "yes" {
|
||||
found = localrange.Contains(ip)
|
||||
|
||||
} else {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return local
|
||||
}
|
||||
|
|
|
@ -2,12 +2,10 @@ package functions
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
@ -19,14 +17,11 @@ import (
|
|||
"github.com/gravitl/netmaker/netclient/auth"
|
||||
"github.com/gravitl/netmaker/netclient/config"
|
||||
"github.com/gravitl/netmaker/netclient/daemon"
|
||||
"github.com/gravitl/netmaker/netclient/local"
|
||||
"github.com/gravitl/netmaker/netclient/ncutils"
|
||||
"github.com/gravitl/netmaker/netclient/wireguard"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
|
||||
// == Message Caches ==
|
||||
// var keepalive = new(sync.Map)
|
||||
var messageCache = new(sync.Map)
|
||||
var networkcontext = new(sync.Map)
|
||||
|
||||
|
@ -38,63 +33,159 @@ type cachedMessage struct {
|
|||
LastSeen time.Time
|
||||
}
|
||||
|
||||
func insert(network, which, cache string) {
|
||||
var newMessage = cachedMessage{
|
||||
Message: cache,
|
||||
LastSeen: time.Now(),
|
||||
}
|
||||
messageCache.Store(fmt.Sprintf("%s%s", network, which), newMessage)
|
||||
}
|
||||
|
||||
func read(network, which string) string {
|
||||
val, isok := messageCache.Load(fmt.Sprintf("%s%s", network, which))
|
||||
if isok {
|
||||
var readMessage = val.(cachedMessage) // fetch current cached message
|
||||
if readMessage.LastSeen.IsZero() {
|
||||
return ""
|
||||
}
|
||||
if time.Now().After(readMessage.LastSeen.Add(time.Minute * 10)) { // check if message has been there over a minute
|
||||
messageCache.Delete(fmt.Sprintf("%s%s", network, which)) // remove old message if expired
|
||||
return ""
|
||||
}
|
||||
return readMessage.Message // return current message if not expired
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// == End Message Caches ==
|
||||
|
||||
// Daemon runs netclient daemon from command line
|
||||
func Daemon() error {
|
||||
networks, err := ncutils.GetSystemNetworks()
|
||||
// == initial pull of all networks ==
|
||||
networks, _ := ncutils.GetSystemNetworks()
|
||||
for _, network := range networks {
|
||||
var cfg config.ClientConfig
|
||||
cfg.Network = network
|
||||
cfg.ReadConfig()
|
||||
initialPull(cfg.Network)
|
||||
}
|
||||
|
||||
// == get all the comms networks on machine ==
|
||||
commsNetworks, err := getCommsNetworks(networks[:])
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.New("no comm networks exist")
|
||||
}
|
||||
for _, network := range networks {
|
||||
|
||||
// == subscribe to all nodes on each comms network on machine ==
|
||||
for currCommsNet := range commsNetworks {
|
||||
ncutils.PrintLog("started comms network daemon, "+currCommsNet, 1)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
networkcontext.Store(network, cancel)
|
||||
go MessageQueue(ctx, network)
|
||||
networkcontext.Store(currCommsNet, cancel)
|
||||
go messageQueue(ctx, currCommsNet)
|
||||
}
|
||||
|
||||
// == add waitgroup and cancel for checkin routine ==
|
||||
wg := sync.WaitGroup{}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
wg.Add(1)
|
||||
go Checkin(ctx, &wg, commsNetworks)
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, syscall.SIGTERM, os.Interrupt)
|
||||
signal.Notify(quit, syscall.SIGTERM, os.Interrupt, os.Kill)
|
||||
<-quit
|
||||
for _, network := range networks {
|
||||
if cancel, ok := networkcontext.Load(network); ok {
|
||||
for currCommsNet := range commsNetworks {
|
||||
if cancel, ok := networkcontext.Load(currCommsNet); ok {
|
||||
cancel.(context.CancelFunc)()
|
||||
}
|
||||
}
|
||||
ncutils.Log("all done")
|
||||
cancel()
|
||||
ncutils.Log("shutting down netclient daemon")
|
||||
wg.Wait()
|
||||
ncutils.Log("shutdown complete")
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// SetupMQTT creates a connection to broker and return client
|
||||
func SetupMQTT(cfg *config.ClientConfig, publish bool) mqtt.Client {
|
||||
// UpdateKeys -- updates private key and returns new publickey
|
||||
func UpdateKeys(nodeCfg *config.ClientConfig, client mqtt.Client) error {
|
||||
ncutils.Log("received message to update wireguard keys for network " + nodeCfg.Network)
|
||||
key, err := wgtypes.GeneratePrivateKey()
|
||||
if err != nil {
|
||||
ncutils.Log("error generating privatekey " + err.Error())
|
||||
return err
|
||||
}
|
||||
file := ncutils.GetNetclientPathSpecific() + nodeCfg.Node.Interface + ".conf"
|
||||
if err := wireguard.UpdatePrivateKey(file, key.String()); err != nil {
|
||||
ncutils.Log("error updating wireguard key " + err.Error())
|
||||
return err
|
||||
}
|
||||
if storeErr := wireguard.StorePrivKey(key.String(), nodeCfg.Network); storeErr != nil {
|
||||
ncutils.Log("failed to save private key" + storeErr.Error())
|
||||
return storeErr
|
||||
}
|
||||
|
||||
nodeCfg.Node.PublicKey = key.PublicKey().String()
|
||||
var commsCfg = getCommsCfgByNode(&nodeCfg.Node)
|
||||
PublishNodeUpdate(&commsCfg, nodeCfg)
|
||||
return nil
|
||||
}
|
||||
|
||||
// PingServer -- checks if server is reachable
|
||||
// use commsCfg only*
|
||||
func PingServer(commsCfg *config.ClientConfig) error {
|
||||
node := getServerAddress(commsCfg)
|
||||
pinger, err := ping.NewPinger(node)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pinger.Timeout = 2 * time.Second
|
||||
pinger.Run()
|
||||
stats := pinger.Statistics()
|
||||
if stats.PacketLoss == 100 {
|
||||
return errors.New("ping error")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// == Private ==
|
||||
|
||||
// sets MQ client subscriptions for a specific node config
|
||||
// should be called for each node belonging to a given comms network
|
||||
func setSubscriptions(client mqtt.Client, nodeCfg *config.ClientConfig) {
|
||||
if nodeCfg.DebugOn {
|
||||
if token := client.Subscribe("#", 0, nil); token.Wait() && token.Error() != nil {
|
||||
ncutils.Log(token.Error().Error())
|
||||
return
|
||||
}
|
||||
ncutils.Log("subscribed to all topics for debugging purposes")
|
||||
}
|
||||
|
||||
if token := client.Subscribe(fmt.Sprintf("update/%s/%s", nodeCfg.Node.Network, nodeCfg.Node.ID), 0, mqtt.MessageHandler(NodeUpdate)); token.Wait() && token.Error() != nil {
|
||||
ncutils.Log(token.Error().Error())
|
||||
return
|
||||
}
|
||||
if nodeCfg.DebugOn {
|
||||
ncutils.Log(fmt.Sprintf("subscribed to node updates for node %s update/%s/%s", nodeCfg.Node.Name, nodeCfg.Node.Network, nodeCfg.Node.ID))
|
||||
}
|
||||
if token := client.Subscribe(fmt.Sprintf("peers/%s/%s", nodeCfg.Node.Network, nodeCfg.Node.ID), 0, mqtt.MessageHandler(UpdatePeers)); token.Wait() && token.Error() != nil {
|
||||
ncutils.Log(token.Error().Error())
|
||||
return
|
||||
}
|
||||
if nodeCfg.DebugOn {
|
||||
ncutils.Log(fmt.Sprintf("subscribed to peer updates for node %s peers/%s/%s", nodeCfg.Node.Name, nodeCfg.Node.Network, nodeCfg.Node.ID))
|
||||
}
|
||||
}
|
||||
|
||||
// on a delete usually, pass in the nodecfg to unsubscribe client broker communications
|
||||
// for the node in nodeCfg
|
||||
func unsubscribeNode(client mqtt.Client, nodeCfg *config.ClientConfig) {
|
||||
client.Unsubscribe(fmt.Sprintf("update/%s/%s", nodeCfg.Node.Network, nodeCfg.Node.ID))
|
||||
var ok = true
|
||||
if token := client.Unsubscribe(fmt.Sprintf("update/%s/%s", nodeCfg.Node.Network, nodeCfg.Node.ID)); token.Wait() && token.Error() != nil {
|
||||
ncutils.PrintLog("unable to unsubscribe from updates for node "+nodeCfg.Node.Name+"\n"+token.Error().Error(), 1)
|
||||
ok = false
|
||||
}
|
||||
if token := client.Unsubscribe(fmt.Sprintf("peers/%s/%s", nodeCfg.Node.Network, nodeCfg.Node.ID)); token.Wait() && token.Error() != nil {
|
||||
ncutils.PrintLog("unable to unsubscribe from peer updates for node "+nodeCfg.Node.Name+"\n"+token.Error().Error(), 1)
|
||||
ok = false
|
||||
}
|
||||
if ok {
|
||||
ncutils.PrintLog("successfully unsubscribed node "+nodeCfg.Node.ID+" : "+nodeCfg.Node.Name, 0)
|
||||
}
|
||||
}
|
||||
|
||||
// sets up Message Queue and subsribes/publishes updates to/from server
|
||||
// the client should subscribe to ALL nodes that exist on unique comms network locally
|
||||
func messageQueue(ctx context.Context, commsNet string) {
|
||||
var commsCfg config.ClientConfig
|
||||
commsCfg.Network = commsNet
|
||||
commsCfg.ReadConfig()
|
||||
ncutils.Log("netclient daemon started for network: " + commsNet)
|
||||
client := setupMQTT(&commsCfg, false)
|
||||
defer client.Disconnect(250)
|
||||
<-ctx.Done()
|
||||
ncutils.Log("shutting down daemon for comms network " + commsNet)
|
||||
}
|
||||
|
||||
// setupMQTT creates a connection to broker and return client
|
||||
// utilizes comms client configs to setup connections
|
||||
func setupMQTT(commsCfg *config.ClientConfig, publish bool) mqtt.Client {
|
||||
opts := mqtt.NewClientOptions()
|
||||
server := getServerAddress(cfg)
|
||||
opts.AddBroker(server + ":1883")
|
||||
id := ncutils.MakeRandomString(23)
|
||||
opts.ClientID = id
|
||||
server := getServerAddress(commsCfg)
|
||||
opts.AddBroker(server + ":1883") // TODO get the appropriate port of the comms mq server
|
||||
opts.ClientID = ncutils.MakeRandomString(23) // helps avoid id duplication on broker
|
||||
opts.SetDefaultPublishHandler(All)
|
||||
opts.SetAutoReconnect(true)
|
||||
opts.SetConnectRetry(true)
|
||||
|
@ -103,43 +194,26 @@ func SetupMQTT(cfg *config.ClientConfig, publish bool) mqtt.Client {
|
|||
opts.SetWriteTimeout(time.Minute)
|
||||
opts.SetOnConnectHandler(func(client mqtt.Client) {
|
||||
if !publish {
|
||||
if cfg.DebugOn {
|
||||
if token := client.Subscribe("#", 0, nil); token.Wait() && token.Error() != nil {
|
||||
ncutils.Log(token.Error().Error())
|
||||
return
|
||||
}
|
||||
ncutils.Log("subscribed to all topics for debugging purposes")
|
||||
networks, err := ncutils.GetSystemNetworks()
|
||||
if err != nil {
|
||||
ncutils.Log("error retriving networks " + err.Error())
|
||||
}
|
||||
if token := client.Subscribe(fmt.Sprintf("update/%s/%s", cfg.Node.Network, cfg.Node.ID), 0, mqtt.MessageHandler(NodeUpdate)); token.Wait() && token.Error() != nil {
|
||||
ncutils.Log(token.Error().Error())
|
||||
return
|
||||
for _, network := range networks {
|
||||
var currNodeCfg config.ClientConfig
|
||||
currNodeCfg.Network = network
|
||||
currNodeCfg.ReadConfig()
|
||||
setSubscriptions(client, &currNodeCfg)
|
||||
}
|
||||
if cfg.DebugOn {
|
||||
ncutils.Log(fmt.Sprintf("subscribed to node updates for node %s update/%s/%s", cfg.Node.Name, cfg.Node.Network, cfg.Node.ID))
|
||||
}
|
||||
if token := client.Subscribe(fmt.Sprintf("peers/%s/%s", cfg.Node.Network, cfg.Node.ID), 0, mqtt.MessageHandler(UpdatePeers)); token.Wait() && token.Error() != nil {
|
||||
ncutils.Log(token.Error().Error())
|
||||
return
|
||||
}
|
||||
if cfg.DebugOn {
|
||||
ncutils.Log(fmt.Sprintf("subscribed to peer updates for node %s peers/%s/%s", cfg.Node.Name, cfg.Node.Network, cfg.Node.ID))
|
||||
}
|
||||
opts.SetOrderMatters(true)
|
||||
opts.SetResumeSubs(true)
|
||||
}
|
||||
})
|
||||
opts.SetOrderMatters(true)
|
||||
opts.SetResumeSubs(true)
|
||||
opts.SetConnectionLostHandler(func(c mqtt.Client, e error) {
|
||||
ncutils.Log("detected broker connection lost, running pull for " + cfg.Node.Network)
|
||||
_, err := Pull(cfg.Node.Network, true)
|
||||
ncutils.Log("detected broker connection lost, running pull for " + commsCfg.Node.Network)
|
||||
_, err := Pull(commsCfg.Node.Network, true)
|
||||
if err != nil {
|
||||
ncutils.Log("could not run pull, server unreachable: " + err.Error())
|
||||
ncutils.Log("waiting to retry...")
|
||||
/*
|
||||
//Consider putting in logic to restart - daemon may take long time to refresh
|
||||
time.Sleep(time.Minute * 5)
|
||||
ncutils.Log("restarting netclient")
|
||||
daemon.Restart()
|
||||
*/
|
||||
}
|
||||
ncutils.Log("connection re-established with mqtt server")
|
||||
})
|
||||
|
@ -149,10 +223,10 @@ func SetupMQTT(cfg *config.ClientConfig, publish bool) mqtt.Client {
|
|||
for {
|
||||
//if after 12 seconds, try a gRPC pull on the last try
|
||||
if time.Now().After(tperiod) {
|
||||
ncutils.Log("running pull for " + cfg.Node.Network)
|
||||
_, err := Pull(cfg.Node.Network, true)
|
||||
ncutils.Log("running pull for " + commsCfg.Node.Network)
|
||||
_, err := Pull(commsCfg.Node.Network, true)
|
||||
if err != nil {
|
||||
ncutils.Log("could not run pull, exiting " + cfg.Node.Network + " setup: " + err.Error())
|
||||
ncutils.Log("could not run pull, exiting " + commsCfg.Node.Network + " setup: " + err.Error())
|
||||
return client
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
|
@ -160,10 +234,10 @@ func SetupMQTT(cfg *config.ClientConfig, publish bool) mqtt.Client {
|
|||
if token := client.Connect(); token.Wait() && token.Error() != nil {
|
||||
ncutils.Log("unable to connect to broker, retrying ...")
|
||||
if time.Now().After(tperiod) {
|
||||
ncutils.Log("could not connect to broker, exiting " + cfg.Node.Network + " setup: " + token.Error().Error())
|
||||
ncutils.Log("could not connect to broker, exiting " + commsCfg.Node.Network + " setup: " + token.Error().Error())
|
||||
if strings.Contains(token.Error().Error(), "connectex") || strings.Contains(token.Error().Error(), "i/o timeout") {
|
||||
ncutils.PrintLog("connection issue detected.. pulling and restarting daemon", 0)
|
||||
Pull(cfg.Node.Network, true)
|
||||
Pull(commsCfg.Node.Network, true)
|
||||
daemon.Restart()
|
||||
}
|
||||
return client
|
||||
|
@ -176,341 +250,14 @@ func SetupMQTT(cfg *config.ClientConfig, publish bool) mqtt.Client {
|
|||
return client
|
||||
}
|
||||
|
||||
// MessageQueue sets up Message Queue and subsribes/publishes updates to/from server
|
||||
func MessageQueue(ctx context.Context, network string) {
|
||||
ncutils.Log("netclient go routine started for " + network)
|
||||
var cfg config.ClientConfig
|
||||
cfg.Network = network
|
||||
initialPull(cfg.Network)
|
||||
|
||||
cfg.ReadConfig()
|
||||
ncutils.Log("daemon started for network: " + network)
|
||||
client := SetupMQTT(&cfg, false)
|
||||
|
||||
defer client.Disconnect(250)
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(2)
|
||||
checkinctx, checkincancel := context.WithCancel(context.Background())
|
||||
go Checkin(checkinctx, wg, &cfg, network)
|
||||
<-ctx.Done()
|
||||
checkincancel()
|
||||
ncutils.Log("shutting down message queue for network " + network)
|
||||
wg.Wait()
|
||||
ncutils.Log("shutdown complete")
|
||||
}
|
||||
|
||||
// All -- mqtt message hander for all ('#') topics
|
||||
var All mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
|
||||
ncutils.Log("default message handler -- received message but not handling")
|
||||
ncutils.Log("Topic: " + string(msg.Topic()))
|
||||
//ncutils.Log("Message: " + string(msg.Payload()))
|
||||
}
|
||||
|
||||
// NodeUpdate -- mqtt message handler for /update/<NodeID> topic
|
||||
func NodeUpdate(client mqtt.Client, msg mqtt.Message) {
|
||||
var newNode models.Node
|
||||
var cfg config.ClientConfig
|
||||
var network = parseNetworkFromTopic(msg.Topic())
|
||||
cfg.Network = network
|
||||
cfg.ReadConfig()
|
||||
|
||||
data, dataErr := decryptMsg(&cfg, msg.Payload())
|
||||
if dataErr != nil {
|
||||
return
|
||||
}
|
||||
err := json.Unmarshal([]byte(data), &newNode)
|
||||
if err != nil {
|
||||
ncutils.Log("error unmarshalling node update data" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
ncutils.Log("received message to update node " + newNode.Name)
|
||||
// see if cache hit, if so skip
|
||||
var currentMessage = read(newNode.Network, lastNodeUpdate)
|
||||
if currentMessage == string(data) {
|
||||
return
|
||||
}
|
||||
insert(newNode.Network, lastNodeUpdate, string(data)) // store new message in cache
|
||||
|
||||
//check if interface name has changed if so delete.
|
||||
if cfg.Node.Interface != newNode.Interface {
|
||||
if err = wireguard.RemoveConf(cfg.Node.Interface, true); err != nil {
|
||||
ncutils.PrintLog("could not delete old interface "+cfg.Node.Interface+": "+err.Error(), 1)
|
||||
}
|
||||
}
|
||||
newNode.PullChanges = "no"
|
||||
//ensure that OS never changes
|
||||
newNode.OS = runtime.GOOS
|
||||
// check if interface needs to delta
|
||||
ifaceDelta := ncutils.IfaceDelta(&cfg.Node, &newNode)
|
||||
shouldDNSChange := cfg.Node.DNSOn != newNode.DNSOn
|
||||
|
||||
cfg.Node = newNode
|
||||
switch newNode.Action {
|
||||
case models.NODE_DELETE:
|
||||
if cancel, ok := networkcontext.Load(newNode.Network); ok {
|
||||
ncutils.Log("cancelling message queue context for " + newNode.Network)
|
||||
cancel.(context.CancelFunc)()
|
||||
} else {
|
||||
ncutils.Log("failed to kill go routines for network " + newNode.Network)
|
||||
}
|
||||
ncutils.PrintLog(fmt.Sprintf("received delete request for %s", cfg.Node.Name), 1)
|
||||
if err = LeaveNetwork(cfg.Node.Network); err != nil {
|
||||
if !strings.Contains("rpc error", err.Error()) {
|
||||
ncutils.PrintLog(fmt.Sprintf("failed to leave, please check that local files for network %s were removed", cfg.Node.Network), 1)
|
||||
}
|
||||
ncutils.PrintLog(fmt.Sprintf("%s was removed", cfg.Node.Name), 1)
|
||||
return
|
||||
}
|
||||
ncutils.PrintLog(fmt.Sprintf("%s was removed", cfg.Node.Name), 1)
|
||||
return
|
||||
case models.NODE_UPDATE_KEY:
|
||||
if err := UpdateKeys(&cfg, client); err != nil {
|
||||
ncutils.PrintLog("err updating wireguard keys: "+err.Error(), 1)
|
||||
}
|
||||
case models.NODE_NOOP:
|
||||
default:
|
||||
}
|
||||
// Save new config
|
||||
cfg.Node.Action = models.NODE_NOOP
|
||||
if err := config.Write(&cfg, cfg.Network); err != nil {
|
||||
ncutils.PrintLog("error updating node configuration: "+err.Error(), 1)
|
||||
}
|
||||
nameserver := cfg.Server.CoreDNSAddr
|
||||
privateKey, err := wireguard.RetrievePrivKey(newNode.Network)
|
||||
if err != nil {
|
||||
ncutils.Log("error reading PrivateKey " + err.Error())
|
||||
return
|
||||
}
|
||||
file := ncutils.GetNetclientPathSpecific() + cfg.Node.Interface + ".conf"
|
||||
if err := wireguard.UpdateWgInterface(file, privateKey, nameserver, newNode); err != nil {
|
||||
ncutils.Log("error updating wireguard config " + err.Error())
|
||||
return
|
||||
}
|
||||
if ifaceDelta {
|
||||
ncutils.Log("applying WG conf to " + file)
|
||||
err = wireguard.ApplyConf(&cfg.Node, cfg.Node.Interface, file)
|
||||
if err != nil {
|
||||
ncutils.Log("error restarting wg after node update " + err.Error())
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Second >> 1)
|
||||
// if err = Resubscribe(client, &cfg); err != nil {
|
||||
// ncutils.Log("error resubscribing after interface change " + err.Error())
|
||||
// return
|
||||
// }
|
||||
if newNode.DNSOn == "yes" {
|
||||
for _, server := range newNode.NetworkSettings.DefaultServerAddrs {
|
||||
if server.IsLeader {
|
||||
go local.SetDNSWithRetry(newNode, server.Address)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//deal with DNS
|
||||
if newNode.DNSOn != "yes" && shouldDNSChange && cfg.Node.Interface != "" {
|
||||
ncutils.Log("settng DNS off")
|
||||
_, err := ncutils.RunCmd("/usr/bin/resolvectl revert "+cfg.Node.Interface, true)
|
||||
if err != nil {
|
||||
ncutils.Log("error applying dns" + err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// UpdatePeers -- mqtt message handler for peers/<Network>/<NodeID> topic
|
||||
func UpdatePeers(client mqtt.Client, msg mqtt.Message) {
|
||||
var peerUpdate models.PeerUpdate
|
||||
var network = parseNetworkFromTopic(msg.Topic())
|
||||
var cfg = config.ClientConfig{}
|
||||
cfg.Network = network
|
||||
cfg.ReadConfig()
|
||||
|
||||
data, dataErr := decryptMsg(&cfg, msg.Payload())
|
||||
if dataErr != nil {
|
||||
return
|
||||
}
|
||||
err := json.Unmarshal([]byte(data), &peerUpdate)
|
||||
if err != nil {
|
||||
ncutils.Log("error unmarshalling peer data")
|
||||
return
|
||||
}
|
||||
// see if cached hit, if so skip
|
||||
var currentMessage = read(peerUpdate.Network, lastPeerUpdate)
|
||||
if currentMessage == string(data) {
|
||||
return
|
||||
}
|
||||
insert(peerUpdate.Network, lastPeerUpdate, string(data))
|
||||
|
||||
file := ncutils.GetNetclientPathSpecific() + cfg.Node.Interface + ".conf"
|
||||
err = wireguard.UpdateWgPeers(file, peerUpdate.Peers)
|
||||
if err != nil {
|
||||
ncutils.Log("error updating wireguard peers" + err.Error())
|
||||
return
|
||||
}
|
||||
//err = wireguard.SyncWGQuickConf(cfg.Node.Interface, file)
|
||||
var iface = cfg.Node.Interface
|
||||
if ncutils.IsMac() {
|
||||
iface, err = local.GetMacIface(cfg.Node.Address)
|
||||
if err != nil {
|
||||
ncutils.Log("error retrieving mac iface: " + err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
err = wireguard.SetPeers(iface, cfg.Node.Address, cfg.Node.PersistentKeepalive, peerUpdate.Peers)
|
||||
if err != nil {
|
||||
ncutils.Log("error syncing wg after peer update: " + err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// MonitorKeepalive - checks time last server keepalive received. If more than 3+ minutes, notify and resubscribe
|
||||
// func MonitorKeepalive(ctx context.Context, wg *sync.WaitGroup, client mqtt.Client, cfg *config.ClientConfig) {
|
||||
// defer wg.Done()
|
||||
// for {
|
||||
// select {
|
||||
// case <-ctx.Done():
|
||||
// ncutils.Log("cancel recieved, monitor keepalive exiting")
|
||||
// return
|
||||
// case <-time.After(time.Second * 150):
|
||||
// var keepalivetime time.Time
|
||||
// keepaliveval, ok := keepalive.Load(cfg.Node.Network)
|
||||
// if ok {
|
||||
// keepalivetime = keepaliveval.(time.Time)
|
||||
// if !keepalivetime.IsZero() && time.Since(keepalivetime) > time.Second*120 { // more than 2+ minutes
|
||||
// // ncutils.Log("server keepalive not recieved recently, resubscribe to message queue")
|
||||
// // err := Resubscribe(client, cfg)
|
||||
// // if err != nil {
|
||||
// // ncutils.Log("closing " + err.Error())
|
||||
// // }
|
||||
// ncutils.Log("maybe wanna call something")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// ServerKeepAlive -- handler to react to keepalive messages published by server
|
||||
// func ServerKeepAlive(client mqtt.Client, msg mqtt.Message) {
|
||||
// var currentTime = time.Now()
|
||||
// keepalive.Store(parseNetworkFromTopic(msg.Topic()), currentTime)
|
||||
// ncutils.PrintLog("received server keepalive at "+currentTime.String(), 2)
|
||||
// }
|
||||
|
||||
// UpdateKeys -- updates private key and returns new publickey
|
||||
func UpdateKeys(cfg *config.ClientConfig, client mqtt.Client) error {
|
||||
ncutils.Log("received message to update keys")
|
||||
key, err := wgtypes.GeneratePrivateKey()
|
||||
if err != nil {
|
||||
ncutils.Log("error generating privatekey " + err.Error())
|
||||
return err
|
||||
}
|
||||
file := ncutils.GetNetclientPathSpecific() + cfg.Node.Interface + ".conf"
|
||||
if err := wireguard.UpdatePrivateKey(file, key.String()); err != nil {
|
||||
ncutils.Log("error updating wireguard key " + err.Error())
|
||||
return err
|
||||
}
|
||||
cfg.Node.PublicKey = key.PublicKey().String()
|
||||
if err := config.ModConfig(&cfg.Node); err != nil {
|
||||
ncutils.Log("error updating local config " + err.Error())
|
||||
}
|
||||
PublishNodeUpdate(cfg)
|
||||
if err = wireguard.ApplyConf(&cfg.Node, cfg.Node.Interface, file); err != nil {
|
||||
ncutils.Log("error applying new config " + err.Error())
|
||||
// publishes a message to server to update peers on this peer's behalf
|
||||
func publishSignal(commsCfg, nodeCfg *config.ClientConfig, signal byte) error {
|
||||
if err := publish(commsCfg, nodeCfg, fmt.Sprintf("signal/%s", nodeCfg.Node.ID), []byte{signal}, 1); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Checkin -- go routine that checks for public or local ip changes, publishes changes
|
||||
// if there are no updates, simply "pings" the server as a checkin
|
||||
func Checkin(ctx context.Context, wg *sync.WaitGroup, cfg *config.ClientConfig, network string) {
|
||||
defer wg.Done()
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
ncutils.Log("Checkin cancelled")
|
||||
return
|
||||
//delay should be configuraable -> use cfg.Node.NetworkSettings.DefaultCheckInInterval ??
|
||||
case <-time.After(time.Second * 60):
|
||||
// ncutils.Log("Checkin running")
|
||||
//read latest config
|
||||
cfg.ReadConfig()
|
||||
if cfg.Node.Roaming == "yes" && cfg.Node.IsStatic != "yes" {
|
||||
extIP, err := ncutils.GetPublicIP()
|
||||
if err != nil {
|
||||
ncutils.PrintLog("error encountered checking ip addresses: "+err.Error(), 1)
|
||||
}
|
||||
if cfg.Node.Endpoint != extIP && extIP != "" {
|
||||
ncutils.PrintLog("endpoint has changed from "+cfg.Node.Endpoint+" to "+extIP, 1)
|
||||
cfg.Node.Endpoint = extIP
|
||||
if err := PublishNodeUpdate(cfg); err != nil {
|
||||
ncutils.Log("could not publish endpoint change")
|
||||
}
|
||||
}
|
||||
intIP, err := getPrivateAddr()
|
||||
if err != nil {
|
||||
ncutils.PrintLog("error encountered checking ip addresses: "+err.Error(), 1)
|
||||
}
|
||||
if cfg.Node.LocalAddress != intIP && intIP != "" {
|
||||
ncutils.PrintLog("local Address has changed from "+cfg.Node.LocalAddress+" to "+intIP, 1)
|
||||
cfg.Node.LocalAddress = intIP
|
||||
if err := PublishNodeUpdate(cfg); err != nil {
|
||||
ncutils.Log("could not publish local address change")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
localIP, err := ncutils.GetLocalIP(cfg.Node.LocalRange)
|
||||
if err != nil {
|
||||
ncutils.PrintLog("error encountered checking ip addresses: "+err.Error(), 1)
|
||||
}
|
||||
if cfg.Node.Endpoint != localIP && localIP != "" {
|
||||
ncutils.PrintLog("endpoint has changed from "+cfg.Node.Endpoint+" to "+localIP, 1)
|
||||
cfg.Node.Endpoint = localIP
|
||||
if err := PublishNodeUpdate(cfg); err != nil {
|
||||
ncutils.Log("could not publish localip change")
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := pingServer(cfg); err != nil {
|
||||
ncutils.PrintLog("could not ping server "+err.Error(), 0)
|
||||
}
|
||||
Hello(cfg, network)
|
||||
// ncutils.Log("Checkin complete")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PublishNodeUpdates -- saves node and pushes changes to broker
|
||||
func PublishNodeUpdate(cfg *config.ClientConfig) error {
|
||||
if err := config.Write(cfg, cfg.Network); err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := json.Marshal(cfg.Node)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = publish(cfg, fmt.Sprintf("update/%s", cfg.Node.ID), data); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Hello -- ping the broker to let server know node is alive and doing fine
|
||||
func Hello(cfg *config.ClientConfig, network string) {
|
||||
if err := publish(cfg, fmt.Sprintf("ping/%s", cfg.Node.ID), []byte(ncutils.Version)); err != nil {
|
||||
ncutils.Log(fmt.Sprintf("error publishing ping, %v", err))
|
||||
ncutils.Log("running pull on " + cfg.Node.Network + " to reconnect")
|
||||
_, err := Pull(cfg.Node.Network, true)
|
||||
if err != nil {
|
||||
ncutils.Log("could not run pull on " + cfg.Node.Network + ", error: " + err.Error())
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// == Private ==
|
||||
|
||||
func initialPull(network string) {
|
||||
ncutils.Log("pulling latest config for " + network)
|
||||
var configPath = fmt.Sprintf("%snetconfig-%s", ncutils.GetNetclientPathSpecific(), network)
|
||||
|
@ -539,67 +286,28 @@ func initialPull(network string) {
|
|||
}
|
||||
}
|
||||
|
||||
func publish(cfg *config.ClientConfig, dest string, msg []byte) error {
|
||||
// setup the keys
|
||||
trafficPrivKey, err := auth.RetrieveTrafficKey(cfg.Node.Network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
serverPubKey, err := ncutils.ConvertBytesToKey(cfg.Node.TrafficKeys.Server)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client := SetupMQTT(cfg, true)
|
||||
defer client.Disconnect(250)
|
||||
encrypted, err := ncutils.BoxEncrypt(msg, serverPubKey, trafficPrivKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if token := client.Publish(dest, 0, false, encrypted); token.Wait() && token.Error() != nil {
|
||||
return token.Error()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseNetworkFromTopic(topic string) string {
|
||||
return strings.Split(topic, "/")[1]
|
||||
}
|
||||
|
||||
func decryptMsg(cfg *config.ClientConfig, msg []byte) ([]byte, error) {
|
||||
// should only ever use node client configs
|
||||
func decryptMsg(nodeCfg *config.ClientConfig, msg []byte) ([]byte, error) {
|
||||
if len(msg) <= 24 { // make sure message is of appropriate length
|
||||
return nil, fmt.Errorf("recieved invalid message from broker %s", string(msg))
|
||||
return nil, fmt.Errorf("recieved invalid message from broker %v", msg)
|
||||
}
|
||||
|
||||
// setup the keys
|
||||
diskKey, keyErr := auth.RetrieveTrafficKey(cfg.Node.Network)
|
||||
diskKey, keyErr := auth.RetrieveTrafficKey(nodeCfg.Node.Network)
|
||||
if keyErr != nil {
|
||||
return nil, keyErr
|
||||
}
|
||||
|
||||
serverPubKey, err := ncutils.ConvertBytesToKey(cfg.Node.TrafficKeys.Server)
|
||||
serverPubKey, err := ncutils.ConvertBytesToKey(nodeCfg.Node.TrafficKeys.Server)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ncutils.BoxDecrypt(msg, serverPubKey, diskKey)
|
||||
}
|
||||
|
||||
func pingServer(cfg *config.ClientConfig) error {
|
||||
node := getServerAddress(cfg)
|
||||
pinger, err := ping.NewPinger(node)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pinger.Timeout = 2 * time.Second
|
||||
pinger.Run()
|
||||
stats := pinger.Statistics()
|
||||
if stats.PacketLoss == 100 {
|
||||
return errors.New("ping error")
|
||||
}
|
||||
return nil
|
||||
return ncutils.DeChunk(msg, serverPubKey, diskKey)
|
||||
}
|
||||
|
||||
func getServerAddress(cfg *config.ClientConfig) string {
|
||||
|
@ -611,3 +319,49 @@ func getServerAddress(cfg *config.ClientConfig) string {
|
|||
}
|
||||
return server.Address
|
||||
}
|
||||
|
||||
func getCommsNetworks(networks []string) (map[string]bool, error) {
|
||||
var cfg config.ClientConfig
|
||||
var response = make(map[string]bool, 1)
|
||||
for _, network := range networks {
|
||||
cfg.Network = network
|
||||
cfg.ReadConfig()
|
||||
response[cfg.Node.CommID] = true
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func getCommsCfgByNode(node *models.Node) config.ClientConfig {
|
||||
var commsCfg config.ClientConfig
|
||||
commsCfg.Network = node.Network
|
||||
commsCfg.ReadConfig()
|
||||
return commsCfg
|
||||
}
|
||||
|
||||
// == Message Caches ==
|
||||
|
||||
func insert(network, which, cache string) {
|
||||
var newMessage = cachedMessage{
|
||||
Message: cache,
|
||||
LastSeen: time.Now(),
|
||||
}
|
||||
messageCache.Store(fmt.Sprintf("%s%s", network, which), newMessage)
|
||||
}
|
||||
|
||||
func read(network, which string) string {
|
||||
val, isok := messageCache.Load(fmt.Sprintf("%s%s", network, which))
|
||||
if isok {
|
||||
var readMessage = val.(cachedMessage) // fetch current cached message
|
||||
if readMessage.LastSeen.IsZero() {
|
||||
return ""
|
||||
}
|
||||
if time.Now().After(readMessage.LastSeen.Add(time.Minute * 10)) { // check if message has been there over a minute
|
||||
messageCache.Delete(fmt.Sprintf("%s%s", network, which)) // remove old message if expired
|
||||
return ""
|
||||
}
|
||||
return readMessage.Message // return current message if not expired
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// == End Message Caches ==
|
||||
|
|
|
@ -25,7 +25,7 @@ import (
|
|||
)
|
||||
|
||||
// JoinNetwork - helps a client join a network
|
||||
func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
|
||||
func JoinNetwork(cfg config.ClientConfig, privateKey string, iscomms bool) error {
|
||||
if cfg.Node.Network == "" {
|
||||
return errors.New("no network provided")
|
||||
}
|
||||
|
@ -103,7 +103,8 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
|
|||
if cfg.Node.MacAddress == "" {
|
||||
macs, err := ncutils.GetMacAddr()
|
||||
if err != nil {
|
||||
return err
|
||||
//if macaddress can't be found set to random string
|
||||
cfg.Node.MacAddress = ncutils.MakeRandomString(18)
|
||||
} else {
|
||||
cfg.Node.MacAddress = macs[0]
|
||||
}
|
||||
|
@ -124,14 +125,14 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
|
|||
cfg.Node.Name = formatName(cfg.Node)
|
||||
// differentiate between client/server here
|
||||
var node = models.Node{
|
||||
Password: cfg.Node.Password,
|
||||
Address: cfg.Node.Address,
|
||||
Address6: cfg.Node.Address6,
|
||||
ID: cfg.Node.ID,
|
||||
MacAddress: cfg.Node.MacAddress,
|
||||
AccessKey: cfg.Server.AccessKey,
|
||||
IsStatic: cfg.Node.IsStatic,
|
||||
Roaming: cfg.Node.Roaming,
|
||||
Password: cfg.Node.Password,
|
||||
Address: cfg.Node.Address,
|
||||
Address6: cfg.Node.Address6,
|
||||
ID: cfg.Node.ID,
|
||||
MacAddress: cfg.Node.MacAddress,
|
||||
AccessKey: cfg.Server.AccessKey,
|
||||
IsStatic: cfg.Node.IsStatic,
|
||||
//Roaming: cfg.Node.Roaming,
|
||||
Network: cfg.Network,
|
||||
ListenPort: cfg.Node.ListenPort,
|
||||
PostUp: cfg.Node.PostUp,
|
||||
|
@ -143,7 +144,6 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
|
|||
DNSOn: cfg.Node.DNSOn,
|
||||
Name: cfg.Node.Name,
|
||||
Endpoint: cfg.Node.Endpoint,
|
||||
SaveConfig: cfg.Node.SaveConfig,
|
||||
UDPHolePunch: cfg.Node.UDPHolePunch,
|
||||
TrafficKeys: cfg.Node.TrafficKeys,
|
||||
OS: runtime.GOOS,
|
||||
|
@ -242,7 +242,8 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
|
|||
go func() {
|
||||
if !local.SetDNSWithRetry(node, server.Address) {
|
||||
cfg.Node.DNSOn = "no"
|
||||
PublishNodeUpdate(&cfg)
|
||||
var currentCommsCfg = getCommsCfgByNode(&cfg.Node)
|
||||
PublishNodeUpdate(¤tCommsCfg, &cfg)
|
||||
}
|
||||
}()
|
||||
break
|
||||
|
@ -250,16 +251,18 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
|
|||
}
|
||||
}
|
||||
|
||||
if cfg.Daemon != "off" {
|
||||
err = daemon.InstallDaemon(cfg)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
daemon.Restart()
|
||||
if !iscomms {
|
||||
if cfg.Daemon != "off" {
|
||||
err = daemon.InstallDaemon(cfg)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
daemon.Restart()
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
// format name appropriately. Set to blank on failure
|
||||
|
|
192
netclient/functions/mqhandlers.go
Normal file
192
netclient/functions/mqhandlers.go
Normal file
|
@ -0,0 +1,192 @@
|
|||
package functions
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
mqtt "github.com/eclipse/paho.mqtt.golang"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/netclient/config"
|
||||
"github.com/gravitl/netmaker/netclient/local"
|
||||
"github.com/gravitl/netmaker/netclient/ncutils"
|
||||
"github.com/gravitl/netmaker/netclient/wireguard"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
|
||||
// All -- mqtt message hander for all ('#') topics
|
||||
var All mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
|
||||
ncutils.Log("default message handler -- received message but not handling")
|
||||
ncutils.Log("Topic: " + string(msg.Topic()))
|
||||
//ncutils.Log("Message: " + string(msg.Payload()))
|
||||
}
|
||||
|
||||
// NodeUpdate -- mqtt message handler for /update/<NodeID> topic
|
||||
func NodeUpdate(client mqtt.Client, msg mqtt.Message) {
|
||||
var newNode models.Node
|
||||
var nodeCfg config.ClientConfig
|
||||
var network = parseNetworkFromTopic(msg.Topic())
|
||||
nodeCfg.Network = network
|
||||
nodeCfg.ReadConfig()
|
||||
var commsCfg = getCommsCfgByNode(&nodeCfg.Node)
|
||||
|
||||
data, dataErr := decryptMsg(&nodeCfg, msg.Payload())
|
||||
if dataErr != nil {
|
||||
return
|
||||
}
|
||||
err := json.Unmarshal([]byte(data), &newNode)
|
||||
if err != nil {
|
||||
ncutils.Log("error unmarshalling node update data" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
ncutils.Log("received message to update node " + newNode.Name)
|
||||
// see if cache hit, if so skip
|
||||
var currentMessage = read(newNode.Network, lastNodeUpdate)
|
||||
if currentMessage == string(data) {
|
||||
return
|
||||
}
|
||||
insert(newNode.Network, lastNodeUpdate, string(data)) // store new message in cache
|
||||
|
||||
// ensure that OS never changes
|
||||
newNode.OS = runtime.GOOS
|
||||
// check if interface needs to delta
|
||||
ifaceDelta := ncutils.IfaceDelta(&nodeCfg.Node, &newNode)
|
||||
shouldDNSChange := nodeCfg.Node.DNSOn != newNode.DNSOn
|
||||
hubChange := nodeCfg.Node.IsHub != newNode.IsHub
|
||||
|
||||
nodeCfg.Node = newNode
|
||||
switch newNode.Action {
|
||||
case models.NODE_DELETE:
|
||||
ncutils.PrintLog(fmt.Sprintf("received delete request for %s", nodeCfg.Node.Name), 0)
|
||||
unsubscribeNode(client, &nodeCfg)
|
||||
if err = LeaveNetwork(nodeCfg.Node.Network, true); err != nil {
|
||||
if !strings.Contains("rpc error", err.Error()) {
|
||||
ncutils.PrintLog(fmt.Sprintf("failed to leave, please check that local files for network %s were removed", nodeCfg.Node.Network), 0)
|
||||
return
|
||||
}
|
||||
}
|
||||
ncutils.PrintLog(fmt.Sprintf("%s was removed", nodeCfg.Node.Name), 0)
|
||||
return
|
||||
case models.NODE_UPDATE_KEY:
|
||||
// == get the current key for node ==
|
||||
oldPrivateKey, retErr := wireguard.RetrievePrivKey(nodeCfg.Network)
|
||||
if retErr != nil {
|
||||
break
|
||||
}
|
||||
if err := UpdateKeys(&nodeCfg, client); err != nil {
|
||||
ncutils.PrintLog("err updating wireguard keys, reusing last key\n"+err.Error(), 0)
|
||||
if key, parseErr := wgtypes.ParseKey(oldPrivateKey); parseErr == nil {
|
||||
wireguard.StorePrivKey(key.String(), nodeCfg.Network)
|
||||
nodeCfg.Node.PublicKey = key.PublicKey().String()
|
||||
}
|
||||
}
|
||||
ifaceDelta = true
|
||||
case models.NODE_NOOP:
|
||||
default:
|
||||
}
|
||||
// Save new config
|
||||
nodeCfg.Node.Action = models.NODE_NOOP
|
||||
if err := config.Write(&nodeCfg, nodeCfg.Network); err != nil {
|
||||
ncutils.PrintLog("error updating node configuration: "+err.Error(), 0)
|
||||
}
|
||||
nameserver := nodeCfg.Server.CoreDNSAddr
|
||||
privateKey, err := wireguard.RetrievePrivKey(newNode.Network)
|
||||
if err != nil {
|
||||
ncutils.Log("error reading PrivateKey " + err.Error())
|
||||
return
|
||||
}
|
||||
file := ncutils.GetNetclientPathSpecific() + nodeCfg.Node.Interface + ".conf"
|
||||
|
||||
if err := wireguard.UpdateWgInterface(file, privateKey, nameserver, newNode); err != nil {
|
||||
ncutils.Log("error updating wireguard config " + err.Error())
|
||||
return
|
||||
}
|
||||
if ifaceDelta { // if a change caused an ifacedelta we need to notify the server to update the peers
|
||||
ncutils.Log("applying WG conf to " + file)
|
||||
err = wireguard.ApplyConf(&nodeCfg.Node, nodeCfg.Node.Interface, file)
|
||||
if err != nil {
|
||||
ncutils.Log("error restarting wg after node update " + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
time.Sleep(time.Second >> 0)
|
||||
if newNode.DNSOn == "yes" {
|
||||
for _, server := range newNode.NetworkSettings.DefaultServerAddrs {
|
||||
if server.IsLeader {
|
||||
go local.SetDNSWithRetry(newNode, server.Address)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
doneErr := publishSignal(&commsCfg, &nodeCfg, ncutils.DONE)
|
||||
if doneErr != nil {
|
||||
ncutils.Log("could not notify server to update peers after interface change")
|
||||
} else {
|
||||
ncutils.Log("signalled finished interface update to server")
|
||||
}
|
||||
} else if hubChange {
|
||||
doneErr := publishSignal(&commsCfg, &nodeCfg, ncutils.DONE)
|
||||
if doneErr != nil {
|
||||
ncutils.Log("could not notify server to update peers after hub change")
|
||||
} else {
|
||||
ncutils.Log("signalled finished hub update to server")
|
||||
}
|
||||
}
|
||||
//deal with DNS
|
||||
if newNode.DNSOn != "yes" && shouldDNSChange && nodeCfg.Node.Interface != "" {
|
||||
ncutils.Log("settng DNS off")
|
||||
_, err := ncutils.RunCmd("/usr/bin/resolvectl revert "+nodeCfg.Node.Interface, true)
|
||||
if err != nil {
|
||||
ncutils.Log("error applying dns" + err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// UpdatePeers -- mqtt message handler for peers/<Network>/<NodeID> topic
|
||||
func UpdatePeers(client mqtt.Client, msg mqtt.Message) {
|
||||
var peerUpdate models.PeerUpdate
|
||||
var network = parseNetworkFromTopic(msg.Topic())
|
||||
var cfg = config.ClientConfig{}
|
||||
cfg.Network = network
|
||||
cfg.ReadConfig()
|
||||
|
||||
data, dataErr := decryptMsg(&cfg, msg.Payload())
|
||||
if dataErr != nil {
|
||||
return
|
||||
}
|
||||
err := json.Unmarshal([]byte(data), &peerUpdate)
|
||||
if err != nil {
|
||||
ncutils.Log("error unmarshalling peer data")
|
||||
return
|
||||
}
|
||||
// see if cached hit, if so skip
|
||||
var currentMessage = read(peerUpdate.Network, lastPeerUpdate)
|
||||
if currentMessage == string(data) {
|
||||
return
|
||||
}
|
||||
insert(peerUpdate.Network, lastPeerUpdate, string(data))
|
||||
|
||||
file := ncutils.GetNetclientPathSpecific() + cfg.Node.Interface + ".conf"
|
||||
err = wireguard.UpdateWgPeers(file, peerUpdate.Peers)
|
||||
if err != nil {
|
||||
ncutils.Log("error updating wireguard peers" + err.Error())
|
||||
return
|
||||
}
|
||||
//err = wireguard.SyncWGQuickConf(cfg.Node.Interface, file)
|
||||
var iface = cfg.Node.Interface
|
||||
if ncutils.IsMac() {
|
||||
iface, err = local.GetMacIface(cfg.Node.Address)
|
||||
if err != nil {
|
||||
ncutils.Log("error retrieving mac iface: " + err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
err = wireguard.SetPeers(iface, &cfg.Node, peerUpdate.Peers)
|
||||
if err != nil {
|
||||
ncutils.Log("error syncing wg after peer update: " + err.Error())
|
||||
return
|
||||
}
|
||||
}
|
143
netclient/functions/mqpublish.go
Normal file
143
netclient/functions/mqpublish.go
Normal file
|
@ -0,0 +1,143 @@
|
|||
package functions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gravitl/netmaker/netclient/auth"
|
||||
"github.com/gravitl/netmaker/netclient/config"
|
||||
"github.com/gravitl/netmaker/netclient/ncutils"
|
||||
)
|
||||
|
||||
// Checkin -- go routine that checks for public or local ip changes, publishes changes
|
||||
// if there are no updates, simply "pings" the server as a checkin
|
||||
func Checkin(ctx context.Context, wg *sync.WaitGroup, currentComms map[string]bool) {
|
||||
defer wg.Done()
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
ncutils.Log("checkin routine closed")
|
||||
return
|
||||
//delay should be configuraable -> use cfg.Node.NetworkSettings.DefaultCheckInInterval ??
|
||||
case <-time.After(time.Second * 60):
|
||||
// ncutils.Log("Checkin running")
|
||||
//read latest config
|
||||
networks, err := ncutils.GetSystemNetworks()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for commsNet := range currentComms {
|
||||
var currCommsCfg config.ClientConfig
|
||||
currCommsCfg.Network = commsNet
|
||||
currCommsCfg.ReadConfig()
|
||||
for _, network := range networks {
|
||||
var nodeCfg config.ClientConfig
|
||||
nodeCfg.Network = network
|
||||
nodeCfg.ReadConfig()
|
||||
if nodeCfg.Node.CommID != commsNet {
|
||||
continue // skip if not on current comms network
|
||||
}
|
||||
if nodeCfg.Node.IsStatic != "yes" {
|
||||
extIP, err := ncutils.GetPublicIP()
|
||||
if err != nil {
|
||||
ncutils.PrintLog("error encountered checking public ip addresses: "+err.Error(), 1)
|
||||
}
|
||||
if nodeCfg.Node.Endpoint != extIP && extIP != "" {
|
||||
ncutils.PrintLog("endpoint has changed from "+nodeCfg.Node.Endpoint+" to "+extIP, 1)
|
||||
nodeCfg.Node.Endpoint = extIP
|
||||
if err := PublishNodeUpdate(&currCommsCfg, &nodeCfg); err != nil {
|
||||
ncutils.Log("could not publish endpoint change")
|
||||
}
|
||||
}
|
||||
intIP, err := getPrivateAddr()
|
||||
if err != nil {
|
||||
ncutils.PrintLog("error encountered checking private ip addresses: "+err.Error(), 1)
|
||||
}
|
||||
if nodeCfg.Node.LocalAddress != intIP && intIP != "" {
|
||||
ncutils.PrintLog("local Address has changed from "+nodeCfg.Node.LocalAddress+" to "+intIP, 1)
|
||||
nodeCfg.Node.LocalAddress = intIP
|
||||
if err := PublishNodeUpdate(&currCommsCfg, &nodeCfg); err != nil {
|
||||
ncutils.Log("could not publish local address change")
|
||||
}
|
||||
}
|
||||
} else if nodeCfg.Node.IsLocal == "yes" && nodeCfg.Node.LocalRange != "" {
|
||||
localIP, err := ncutils.GetLocalIP(nodeCfg.Node.LocalRange)
|
||||
if err != nil {
|
||||
ncutils.PrintLog("error encountered checking local ip addresses: "+err.Error(), 1)
|
||||
}
|
||||
if nodeCfg.Node.Endpoint != localIP && localIP != "" {
|
||||
ncutils.PrintLog("endpoint has changed from "+nodeCfg.Node.Endpoint+" to "+localIP, 1)
|
||||
nodeCfg.Node.Endpoint = localIP
|
||||
if err := PublishNodeUpdate(&currCommsCfg, &nodeCfg); err != nil {
|
||||
ncutils.Log("could not publish localip change")
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := PingServer(&currCommsCfg); err != nil {
|
||||
ncutils.PrintLog("could not ping server on comms net, "+currCommsCfg.Network+"\n"+err.Error(), 0)
|
||||
} else {
|
||||
Hello(&currCommsCfg, &nodeCfg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PublishNodeUpdates -- saves node and pushes changes to broker
|
||||
func PublishNodeUpdate(commsCfg, nodeCfg *config.ClientConfig) error {
|
||||
if err := config.Write(nodeCfg, nodeCfg.Network); err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := json.Marshal(nodeCfg.Node)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = publish(commsCfg, nodeCfg, fmt.Sprintf("update/%s", nodeCfg.Node.ID), data, 1); err != nil {
|
||||
return err
|
||||
}
|
||||
ncutils.PrintLog("sent a node update to server for node"+nodeCfg.Node.Name+", "+nodeCfg.Node.ID, 1)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Hello -- ping the broker to let server know node it's alive and well
|
||||
func Hello(commsCfg, nodeCfg *config.ClientConfig) {
|
||||
if err := publish(commsCfg, nodeCfg, fmt.Sprintf("ping/%s", nodeCfg.Node.ID), []byte(ncutils.Version), 0); err != nil {
|
||||
ncutils.Log(fmt.Sprintf("error publishing ping, %v", err))
|
||||
ncutils.Log("running pull on " + commsCfg.Node.Network + " to reconnect")
|
||||
_, err := Pull(commsCfg.Node.Network, true)
|
||||
if err != nil {
|
||||
ncutils.Log("could not run pull on " + commsCfg.Node.Network + ", error: " + err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// requires the commscfg in which to send traffic over and nodecfg of node that is publish the message
|
||||
// node cfg is so that the traffic keys of that node may be fetched for encryption
|
||||
func publish(commsCfg, nodeCfg *config.ClientConfig, dest string, msg []byte, qos byte) error {
|
||||
// setup the keys
|
||||
trafficPrivKey, err := auth.RetrieveTrafficKey(nodeCfg.Node.Network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
serverPubKey, err := ncutils.ConvertBytesToKey(nodeCfg.Node.TrafficKeys.Server)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client := setupMQTT(commsCfg, true)
|
||||
defer client.Disconnect(250)
|
||||
encrypted, err := ncutils.Chunk(msg, serverPubKey, trafficPrivKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if token := client.Publish(dest, qos, false, encrypted); token.Wait() && token.Error() != nil {
|
||||
return token.Error()
|
||||
}
|
||||
return nil
|
||||
}
|
126
netclient/functions/pull.go
Normal file
126
netclient/functions/pull.go
Normal file
|
@ -0,0 +1,126 @@
|
|||
package functions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
nodepb "github.com/gravitl/netmaker/grpc"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/netclient/auth"
|
||||
"github.com/gravitl/netmaker/netclient/config"
|
||||
"github.com/gravitl/netmaker/netclient/local"
|
||||
"github.com/gravitl/netmaker/netclient/ncutils"
|
||||
"github.com/gravitl/netmaker/netclient/wireguard"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/metadata"
|
||||
//homedir "github.com/mitchellh/go-homedir"
|
||||
)
|
||||
|
||||
// Pull - pulls the latest config from the server, if manual it will overwrite
|
||||
func Pull(network string, manual bool) (*models.Node, error) {
|
||||
cfg, err := config.ReadConfig(network)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
node := cfg.Node
|
||||
//servercfg := cfg.Server
|
||||
|
||||
if cfg.Node.IPForwarding == "yes" && !ncutils.IsWindows() {
|
||||
if err = local.SetIPForwarding(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
var resNode models.Node // just need to fill this with either server calls or client calls
|
||||
|
||||
var header metadata.MD
|
||||
var wcclient nodepb.NodeServiceClient
|
||||
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
|
||||
}
|
||||
data, err := json.Marshal(&node)
|
||||
if err != nil {
|
||||
ncutils.PrintLog("Failed to parse node config: "+err.Error(), 1)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := &nodepb.Object{
|
||||
Data: string(data),
|
||||
Type: nodepb.NODE_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
|
||||
}
|
||||
}
|
||||
// ensure that the OS never changes
|
||||
resNode.OS = runtime.GOOS
|
||||
if manual {
|
||||
// check for interface change
|
||||
if cfg.Node.Interface != resNode.Interface {
|
||||
if err = DeleteInterface(cfg.Node.Interface, cfg.Node.PostDown); err != nil {
|
||||
ncutils.PrintLog("could not delete old interface "+cfg.Node.Interface, 1)
|
||||
}
|
||||
}
|
||||
if err = config.ModConfig(&resNode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = wireguard.SetWGConfig(network, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nodeData, err := json.Marshal(&resNode)
|
||||
if err != nil {
|
||||
return &resNode, err
|
||||
}
|
||||
|
||||
if resNode.IsServer != "yes" {
|
||||
if wcclient == nil || ctx == nil {
|
||||
return &cfg.Node, errors.New("issue initializing gRPC client")
|
||||
}
|
||||
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 {
|
||||
if err = wireguard.SetWGConfig(network, true); err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) && !ncutils.IsFreeBSD() {
|
||||
return Pull(network, true)
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
var bkupErr = config.SaveBackup(network)
|
||||
if bkupErr != nil {
|
||||
ncutils.Log("unable to update backup file")
|
||||
}
|
||||
|
||||
return &resNode, err
|
||||
}
|
8
netclient/ncutils/constants.go
Normal file
8
netclient/ncutils/constants.go
Normal file
|
@ -0,0 +1,8 @@
|
|||
package ncutils
|
||||
|
||||
const (
|
||||
// ACK - acknowledgement signal for MQ
|
||||
ACK = 1
|
||||
// DONE - done signal for MQ
|
||||
DONE = 2
|
||||
)
|
105
netclient/ncutils/encryption.go
Normal file
105
netclient/ncutils/encryption.go
Normal file
|
@ -0,0 +1,105 @@
|
|||
package ncutils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"golang.org/x/crypto/nacl/box"
|
||||
)
|
||||
|
||||
const (
|
||||
chunkSize = 16000 // 16000 bytes max message size
|
||||
)
|
||||
|
||||
// BoxEncrypt - encrypts traffic box
|
||||
func BoxEncrypt(message []byte, recipientPubKey *[32]byte, senderPrivateKey *[32]byte) ([]byte, error) {
|
||||
var nonce [24]byte // 192 bits of randomization
|
||||
if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
encrypted := box.Seal(nonce[:], message, &nonce, recipientPubKey, senderPrivateKey)
|
||||
return encrypted, nil
|
||||
}
|
||||
|
||||
// BoxDecrypt - decrypts traffic box
|
||||
func BoxDecrypt(encrypted []byte, senderPublicKey *[32]byte, recipientPrivateKey *[32]byte) ([]byte, error) {
|
||||
var decryptNonce [24]byte
|
||||
copy(decryptNonce[:], encrypted[:24])
|
||||
decrypted, ok := box.Open(nil, encrypted[24:], &decryptNonce, senderPublicKey, recipientPrivateKey)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("could not decrypt message, %v", encrypted)
|
||||
}
|
||||
return decrypted, nil
|
||||
}
|
||||
|
||||
// Chunk - chunks a message and encrypts each chunk
|
||||
func Chunk(message []byte, recipientPubKey *[32]byte, senderPrivateKey *[32]byte) ([]byte, error) {
|
||||
var chunks [][]byte
|
||||
for i := 0; i < len(message); i += chunkSize {
|
||||
end := i + chunkSize
|
||||
|
||||
if end > len(message) {
|
||||
end = len(message)
|
||||
}
|
||||
|
||||
encryptedMsgSlice, err := BoxEncrypt(message[i:end], recipientPubKey, senderPrivateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
chunks = append(chunks, encryptedMsgSlice)
|
||||
}
|
||||
|
||||
chunkedMsg, err := convertBytesToMsg(chunks) // encode the array into some bytes to decode on receiving end
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return chunkedMsg, nil
|
||||
}
|
||||
|
||||
// DeChunk - "de" chunks and decrypts a message
|
||||
func DeChunk(chunkedMsg []byte, senderPublicKey *[32]byte, recipientPrivateKey *[32]byte) ([]byte, error) {
|
||||
chunks, err := convertMsgToBytes(chunkedMsg) // convert the message to it's original chunks form
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var totalMsg []byte
|
||||
for i := range chunks {
|
||||
decodedMsg, err := BoxDecrypt(chunks[i], senderPublicKey, recipientPrivateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
totalMsg = append(totalMsg, decodedMsg...)
|
||||
}
|
||||
return totalMsg, nil
|
||||
}
|
||||
|
||||
// == private ==
|
||||
|
||||
var splitKey = []byte("|(,)(,)|")
|
||||
|
||||
// ConvertMsgToBytes - converts a message (MQ) to it's chunked version
|
||||
// decode action
|
||||
func convertMsgToBytes(msg []byte) ([][]byte, error) {
|
||||
splitMsg := bytes.Split(msg, splitKey)
|
||||
return splitMsg, nil
|
||||
}
|
||||
|
||||
// ConvertBytesToMsg - converts the chunked message into a MQ message
|
||||
// encode action
|
||||
func convertBytesToMsg(b [][]byte) ([]byte, error) {
|
||||
|
||||
var buffer []byte // allocate a buffer with adequate sizing
|
||||
for i := range b { // append bytes to it with key
|
||||
buffer = append(buffer, b[i]...)
|
||||
if i != len(b)-1 {
|
||||
buffer = append(buffer, splitKey...)
|
||||
}
|
||||
}
|
||||
return buffer, nil
|
||||
}
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/gravitl/netmaker/models"
|
||||
)
|
||||
|
||||
// IfaceDelta - checks if the new node causes an interface change
|
||||
func IfaceDelta(currentNode *models.Node, newNode *models.Node) bool {
|
||||
// single comparison statements
|
||||
if newNode.Endpoint != currentNode.Endpoint ||
|
||||
|
@ -15,11 +16,12 @@ func IfaceDelta(currentNode *models.Node, newNode *models.Node) bool {
|
|||
newNode.IsEgressGateway != currentNode.IsEgressGateway ||
|
||||
newNode.IsIngressGateway != currentNode.IsIngressGateway ||
|
||||
newNode.IsRelay != currentNode.IsRelay ||
|
||||
newNode.ListenPort != currentNode.ListenPort ||
|
||||
newNode.UDPHolePunch != currentNode.UDPHolePunch ||
|
||||
newNode.MTU != currentNode.MTU ||
|
||||
newNode.IsPending != currentNode.IsPending ||
|
||||
newNode.PersistentKeepalive != currentNode.PersistentKeepalive ||
|
||||
newNode.DNSOn != currentNode.DNSOn ||
|
||||
len(newNode.ExcludedAddrs) != len(currentNode.ExcludedAddrs) ||
|
||||
len(newNode.AllowedIPs) != len(currentNode.AllowedIPs) {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package ncutils
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
crand "crypto/rand"
|
||||
"crypto/tls"
|
||||
"encoding/gob"
|
||||
"errors"
|
||||
|
@ -22,7 +21,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"golang.org/x/crypto/nacl/box"
|
||||
"golang.zx2c4.com/wireguard/wgctrl"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
"google.golang.org/grpc"
|
||||
|
@ -51,7 +49,7 @@ const LINUX_APP_DATA_PATH = "/etc/netclient"
|
|||
const WINDOWS_APP_DATA_PATH = "C:\\ProgramData\\Netclient"
|
||||
|
||||
// WINDOWS_APP_DATA_PATH - windows path
|
||||
const WINDOWS_WG_DPAPI_PATH = "C:\\Program Files\\WireGuard\\Data\\Configurations"
|
||||
//const WINDOWS_WG_DPAPI_PATH = "C:\\Program Files\\WireGuard\\Data\\Configurations"
|
||||
|
||||
// WINDOWS_SVC_NAME - service name
|
||||
const WINDOWS_SVC_NAME = "netclient"
|
||||
|
@ -104,6 +102,12 @@ func IsFreeBSD() bool {
|
|||
return runtime.GOOS == "freebsd"
|
||||
}
|
||||
|
||||
// HasWGQuick - checks if WGQuick command is present
|
||||
func HasWgQuick() bool {
|
||||
cmd, err := exec.LookPath("wg-quick")
|
||||
return err == nil && cmd != ""
|
||||
}
|
||||
|
||||
// GetWireGuard - checks if wg is installed
|
||||
func GetWireGuard() string {
|
||||
userspace := os.Getenv("WG_QUICK_USERSPACE_IMPLEMENTATION")
|
||||
|
@ -613,28 +617,6 @@ func ServerAddrSliceContains(slice []models.ServerAddr, item models.ServerAddr)
|
|||
return false
|
||||
}
|
||||
|
||||
// BoxEncrypt - encrypts traffic box
|
||||
func BoxEncrypt(message []byte, recipientPubKey *[32]byte, senderPrivateKey *[32]byte) ([]byte, error) {
|
||||
var nonce [24]byte // 192 bits of randomization
|
||||
if _, err := io.ReadFull(crand.Reader, nonce[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
encrypted := box.Seal(nonce[:], message, &nonce, recipientPubKey, senderPrivateKey)
|
||||
return encrypted, nil
|
||||
}
|
||||
|
||||
// BoxDecrypt - decrypts traffic box
|
||||
func BoxDecrypt(encrypted []byte, senderPublicKey *[32]byte, recipientPrivateKey *[32]byte) ([]byte, error) {
|
||||
var decryptNonce [24]byte
|
||||
copy(decryptNonce[:], encrypted[:24])
|
||||
decrypted, ok := box.Open(nil, encrypted[24:], &decryptNonce, senderPublicKey, recipientPrivateKey)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("could not decrypt message")
|
||||
}
|
||||
return decrypted, nil
|
||||
}
|
||||
|
||||
// MakeRandomString - generates a random string of len n
|
||||
func MakeRandomString(n int) string {
|
||||
sb := strings.Builder{}
|
||||
|
|
|
@ -28,5 +28,3 @@ func RunCmdFormatted(command string, printerr bool) (string, error) {
|
|||
func GetEmbedded() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity
|
||||
version="0.10.0.0"
|
||||
version="0.11.0.0"
|
||||
processorArchitecture="*"
|
||||
name="netclient.exe"
|
||||
type="win32"
|
||||
|
|
BIN
netclient/netclient.syso
Normal file
BIN
netclient/netclient.syso
Normal file
Binary file not shown.
|
@ -29,7 +29,7 @@
|
|||
"OriginalFilename": "",
|
||||
"PrivateBuild": "",
|
||||
"ProductName": "Netclient",
|
||||
"ProductVersion": "v0.10.0.0",
|
||||
"ProductVersion": "v0.11.0.0",
|
||||
"SpecialBuild": ""
|
||||
},
|
||||
"VarFileInfo": {
|
||||
|
|
|
@ -25,8 +25,10 @@ const (
|
|||
)
|
||||
|
||||
// SetPeers - sets peers on a given WireGuard interface
|
||||
func SetPeers(iface, currentNodeAddr string, keepalive int32, peers []wgtypes.PeerConfig) error {
|
||||
func SetPeers(iface string, node *models.Node, peers []wgtypes.PeerConfig) error {
|
||||
var devicePeers []wgtypes.Peer
|
||||
var currentNodeAddr = node.Address
|
||||
var keepalive = node.PersistentKeepalive
|
||||
var oldPeerAllowedIps = make(map[string][]net.IPNet, len(peers))
|
||||
var err error
|
||||
if ncutils.IsFreeBSD() {
|
||||
|
@ -73,13 +75,14 @@ func SetPeers(iface, currentNodeAddr string, keepalive int32, peers []wgtypes.Pe
|
|||
if keepAliveString == "0" {
|
||||
keepAliveString = "15"
|
||||
}
|
||||
if peer.Endpoint != nil {
|
||||
if node.IsHub == "yes" || peer.Endpoint == nil {
|
||||
_, err = ncutils.RunCmd("wg set "+iface+" peer "+peer.PublicKey.String()+
|
||||
" endpoint "+udpendpoint+
|
||||
" persistent-keepalive "+keepAliveString+
|
||||
" allowed-ips "+allowedips, true)
|
||||
|
||||
} else {
|
||||
_, err = ncutils.RunCmd("wg set "+iface+" peer "+peer.PublicKey.String()+
|
||||
" endpoint "+udpendpoint+
|
||||
" persistent-keepalive "+keepAliveString+
|
||||
" allowed-ips "+allowedips, true)
|
||||
}
|
||||
|
@ -94,6 +97,10 @@ func SetPeers(iface, currentNodeAddr string, keepalive int32, peers []wgtypes.Pe
|
|||
if peer.AllowedIPs[0].String() == currentPeer.AllowedIPs[0].String() {
|
||||
shouldDelete = false
|
||||
}
|
||||
// re-check this if logic is not working, added in case of allowedips not working
|
||||
if peer.PublicKey.String() == currentPeer.PublicKey.String() {
|
||||
shouldDelete = false
|
||||
}
|
||||
}
|
||||
if shouldDelete {
|
||||
output, err := ncutils.RunCmd("wg set "+iface+" peer "+currentPeer.PublicKey.String()+" remove", true)
|
||||
|
@ -131,10 +138,6 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
|
|||
return err
|
||||
}
|
||||
nodecfg := modcfg.Node
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("failed to open client: %v", err)
|
||||
}
|
||||
var ifacename string
|
||||
if nodecfg.Interface != "" {
|
||||
ifacename = nodecfg.Interface
|
||||
|
@ -206,7 +209,13 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
|
|||
if syncconf { // should never be called really.
|
||||
err = SyncWGQuickConf(ifacename, confPath)
|
||||
}
|
||||
|
||||
if !ncutils.HasWgQuick() && ncutils.IsLinux() {
|
||||
err = SetPeers(ifacename, node, peers)
|
||||
if err != nil {
|
||||
ncutils.PrintLog("error setting peers: "+err.Error(), 1)
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
_, cidr, cidrErr := net.ParseCIDR(modcfg.NetworkSettings.AddressRange)
|
||||
if cidrErr == nil {
|
||||
local.SetCIDRRoute(ifacename, node.Address, cidr)
|
||||
|
@ -245,7 +254,7 @@ func SetWGConfig(network string, peerupdate bool) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
err = SetPeers(iface, nodecfg.Address, nodecfg.PersistentKeepalive, peers)
|
||||
err = SetPeers(iface, &nodecfg, peers)
|
||||
} else if peerupdate {
|
||||
err = InitWireguard(&nodecfg, privkey, peers, hasGateway, gateways, true)
|
||||
} else {
|
||||
|
@ -260,8 +269,13 @@ func SetWGConfig(network string, peerupdate bool) error {
|
|||
// RemoveConf - removes a configuration for a given WireGuard interface
|
||||
func RemoveConf(iface string, printlog bool) error {
|
||||
os := runtime.GOOS
|
||||
if !ncutils.HasWgQuick() {
|
||||
os = "nowgquick"
|
||||
}
|
||||
var err error
|
||||
switch os {
|
||||
case "nowgquick":
|
||||
err = RemoveWithoutWGQuick(iface)
|
||||
case "windows":
|
||||
err = RemoveWindowsConf(iface, printlog)
|
||||
case "darwin":
|
||||
|
@ -276,15 +290,29 @@ func RemoveConf(iface string, printlog bool) error {
|
|||
// ApplyConf - applys a conf on disk to WireGuard interface
|
||||
func ApplyConf(node *models.Node, ifacename string, confPath string) error {
|
||||
os := runtime.GOOS
|
||||
if ncutils.IsLinux() && !ncutils.HasWgQuick() {
|
||||
os = "nowgquick"
|
||||
}
|
||||
var err error
|
||||
switch os {
|
||||
case "nowgquick":
|
||||
ApplyWithoutWGQuick(node, ifacename, confPath)
|
||||
case "windows":
|
||||
_ = ApplyWindowsConf(confPath)
|
||||
ApplyWindowsConf(confPath)
|
||||
case "darwin":
|
||||
_ = ApplyMacOSConf(node, ifacename, confPath)
|
||||
ApplyMacOSConf(node, ifacename, confPath)
|
||||
default:
|
||||
err = ApplyWGQuickConf(confPath, ifacename)
|
||||
ApplyWGQuickConf(confPath, ifacename)
|
||||
}
|
||||
|
||||
var nodeCfg config.ClientConfig
|
||||
nodeCfg.Network = node.Network
|
||||
nodeCfg.ReadConfig()
|
||||
ip, cidr, err := net.ParseCIDR(nodeCfg.NetworkSettings.AddressRange)
|
||||
if err == nil {
|
||||
local.SetCIDRRoute(node.Interface, ip.String(), cidr)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
135
netclient/wireguard/noquick.go
Normal file
135
netclient/wireguard/noquick.go
Normal file
|
@ -0,0 +1,135 @@
|
|||
package wireguard
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/netclient/config"
|
||||
"github.com/gravitl/netmaker/netclient/ncutils"
|
||||
"golang.zx2c4.com/wireguard/wgctrl"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
|
||||
// ApplyWithoutWGQuick - Function for running the equivalent of "wg-quick up" for linux if wg-quick is missing
|
||||
func ApplyWithoutWGQuick(node *models.Node, ifacename string, confPath string) error {
|
||||
|
||||
ipExec, err := exec.LookPath("ip")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
wgclient, err := wgctrl.New()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer wgclient.Close()
|
||||
|
||||
privkey, err := RetrievePrivKey(node.Network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key, err := wgtypes.ParseKey(privkey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conf := wgtypes.Config{}
|
||||
nodeport := int(node.ListenPort)
|
||||
if node.UDPHolePunch == "yes" &&
|
||||
node.IsServer == "no" &&
|
||||
node.IsIngressGateway != "yes" &&
|
||||
node.IsStatic != "yes" {
|
||||
conf = wgtypes.Config{
|
||||
PrivateKey: &key,
|
||||
}
|
||||
} else {
|
||||
conf = wgtypes.Config{
|
||||
PrivateKey: &key,
|
||||
ListenPort: &nodeport,
|
||||
}
|
||||
}
|
||||
|
||||
netmaskArr := strings.Split(node.NetworkSettings.AddressRange, "/")
|
||||
var netmask = "32"
|
||||
if len(netmaskArr) == 2 {
|
||||
netmask = netmaskArr[1]
|
||||
}
|
||||
setKernelDevice(ifacename, node.Address, netmask)
|
||||
|
||||
_, err = wgclient.Device(ifacename)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return errors.New("Unknown config error: " + err.Error())
|
||||
}
|
||||
}
|
||||
err = wgclient.ConfigureDevice(ifacename, conf)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
ncutils.PrintLog("Could not configure device: "+err.Error(), 0)
|
||||
}
|
||||
}
|
||||
if _, err := ncutils.RunCmd(ipExec+" link set down dev "+ifacename, false); err != nil {
|
||||
logger.Log(2, "attempted to remove interface before editing")
|
||||
return err
|
||||
}
|
||||
if node.PostDown != "" {
|
||||
runcmds := strings.Split(node.PostDown, "; ")
|
||||
_ = ncutils.RunCmds(runcmds, false)
|
||||
}
|
||||
// set MTU of node interface
|
||||
if _, err := ncutils.RunCmd(ipExec+" link set mtu "+strconv.Itoa(int(node.MTU))+" up dev "+ifacename, true); err != nil {
|
||||
logger.Log(2, "failed to create interface with mtu", strconv.Itoa(int(node.MTU)), "-", ifacename)
|
||||
return err
|
||||
}
|
||||
if node.PostUp != "" {
|
||||
runcmds := strings.Split(node.PostUp, "; ")
|
||||
_ = ncutils.RunCmds(runcmds, true)
|
||||
}
|
||||
if node.Address6 != "" && node.IsDualStack == "yes" {
|
||||
logger.Log(1, "adding address:", node.Address6)
|
||||
_, _ = ncutils.RunCmd(ipExec+" address add dev "+ifacename+" "+node.Address6+"/64", true)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveWithoutWGQuick - Function for running the equivalent of "wg-quick down" for linux if wg-quick is missing
|
||||
func RemoveWithoutWGQuick(ifacename string) error {
|
||||
ipExec, err := exec.LookPath("ip")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out, err := ncutils.RunCmd(ipExec+" link del "+ifacename, false)
|
||||
dontprint := strings.Contains(out, "does not exist") || strings.Contains(out, "Cannot find device")
|
||||
if err != nil && !dontprint {
|
||||
logger.Log(1, "error running command:", ipExec, "link del", ifacename)
|
||||
logger.Log(1, out)
|
||||
}
|
||||
network := strings.ReplaceAll(ifacename, "nm-", "")
|
||||
nodeconf, err := config.ReadConfig(network)
|
||||
if nodeconf != nil && err == nil {
|
||||
if nodeconf.Node.PostDown != "" {
|
||||
runcmds := strings.Split(nodeconf.Node.PostDown, "; ")
|
||||
_ = ncutils.RunCmds(runcmds, false)
|
||||
}
|
||||
} else if err != nil {
|
||||
ncutils.PrintLog("error retrieving config: "+err.Error(), 1)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func setKernelDevice(ifacename, address, mask string) error {
|
||||
ipExec, err := exec.LookPath("ip")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// == best effort ==
|
||||
ncutils.RunCmd("ip link delete dev "+ifacename, false)
|
||||
ncutils.RunCmd(ipExec+" link add dev "+ifacename+" type wireguard", true)
|
||||
ncutils.RunCmd(ipExec+" address add dev "+ifacename+" "+address+"/"+mask, true) // this was a bug waiting to happen
|
||||
|
||||
return nil
|
||||
}
|
|
@ -65,6 +65,7 @@ func ApplyWGQuickConf(confPath string, ifacename string) error {
|
|||
ncutils.RunCmd("wg-quick down "+confPath, true)
|
||||
}
|
||||
_, err = ncutils.RunCmd("wg-quick up "+confPath, true)
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,23 +2,22 @@ package wireguard
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gravitl/netmaker/netclient/ncutils"
|
||||
)
|
||||
|
||||
// ApplyWindowsConf - applies the WireGuard configuration file on Windows
|
||||
func ApplyWindowsConf(confPath string) error {
|
||||
pathStrings := strings.Split(confPath, ncutils.GetWGPathSpecific())
|
||||
if len(pathStrings) == 2 {
|
||||
copyConfPath := fmt.Sprintf("%s\\%s", ncutils.WINDOWS_WG_DPAPI_PATH, pathStrings[1])
|
||||
err := ncutils.Copy(confPath, copyConfPath)
|
||||
if err != nil {
|
||||
ncutils.PrintLog(err.Error(), 1)
|
||||
/*
|
||||
pathStrings := strings.Split(confPath, ncutils.GetWGPathSpecific())
|
||||
if len(pathStrings) == 2 {
|
||||
copyConfPath := fmt.Sprintf("%s\\%s", ncutils.WINDOWS_WG_DPAPI_PATH, pathStrings[1])
|
||||
err := ncutils.Copy(confPath, copyConfPath)
|
||||
if err != nil {
|
||||
ncutils.PrintLog(err.Error(), 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
var commandLine = fmt.Sprintf(`wireguard.exe /installtunnelservice "%s"`, confPath)
|
||||
if _, err := ncutils.RunCmdFormatted(commandLine, false); err != nil {
|
||||
return err
|
||||
|
@ -31,20 +30,22 @@ func RemoveWindowsConf(ifacename string, printlog bool) error {
|
|||
if _, err := ncutils.RunCmd("wireguard.exe /uninstalltunnelservice "+ifacename, printlog); err != nil {
|
||||
ncutils.PrintLog(err.Error(), 1)
|
||||
}
|
||||
dpapipath := fmt.Sprintf("%s\\%s.conf.dpapi", ncutils.WINDOWS_WG_DPAPI_PATH, ifacename)
|
||||
confpath := fmt.Sprintf("%s\\%s.conf", ncutils.WINDOWS_WG_DPAPI_PATH, ifacename)
|
||||
if ncutils.FileExists(confpath) {
|
||||
err := os.Remove(confpath)
|
||||
if err != nil {
|
||||
ncutils.PrintLog(err.Error(), 1)
|
||||
/*
|
||||
dpapipath := fmt.Sprintf("%s\\%s.conf.dpapi", ncutils.WINDOWS_WG_DPAPI_PATH, ifacename)
|
||||
confpath := fmt.Sprintf("%s\\%s.conf", ncutils.WINDOWS_WG_DPAPI_PATH, ifacename)
|
||||
if ncutils.FileExists(confpath) {
|
||||
err := os.Remove(confpath)
|
||||
if err != nil {
|
||||
ncutils.PrintLog(err.Error(), 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
time.Sleep(time.Second >> 2)
|
||||
if ncutils.FileExists(dpapipath) {
|
||||
err := os.Remove(dpapipath)
|
||||
if err != nil {
|
||||
ncutils.PrintLog(err.Error(), 1)
|
||||
time.Sleep(time.Second >> 2)
|
||||
if ncutils.FileExists(dpapipath) {
|
||||
err := os.Remove(dpapipath)
|
||||
if err != nil {
|
||||
ncutils.PrintLog(err.Error(), 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -18,3 +18,4 @@ env CGO_ENABLED=0 GOOS=freebsd GOARCH=arm GOARM=6 go build -ldflags="-X 'main.ve
|
|||
env CGO_ENABLED=0 GOOS=freebsd GOARCH=arm GOARM=7 go build -ldflags="-X 'main.version=$VERSION'" -o build/netclient-freebsd-arm7 main.go
|
||||
env CGO_ENABLED=0 GOOS=freebsd GOARCH=arm64 go build -ldflags="-X 'main.version=$VERSION'" -o build/netclient-freebsd-arm64 main.go
|
||||
env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags="-X 'main.version=$VERSION'" -o build/netclient-darwin main.go
|
||||
env CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags="-X 'main.version=${VERSION}'" -o build/netclient-darwin-arm64 main.go
|
|
@ -12,7 +12,10 @@ import (
|
|||
"github.com/gravitl/netmaker/config"
|
||||
)
|
||||
|
||||
var Version = "dev"
|
||||
var (
|
||||
Version = "dev"
|
||||
commsID = ""
|
||||
)
|
||||
|
||||
// SetHost - sets the host ip
|
||||
func SetHost() error {
|
||||
|
@ -31,16 +34,17 @@ func GetServerConfig() config.ServerConfig {
|
|||
cfg.CoreDNSAddr = GetCoreDNSAddr()
|
||||
cfg.APIHost = GetAPIHost()
|
||||
cfg.APIPort = GetAPIPort()
|
||||
cfg.GRPCConnString = GetGRPCConnString()
|
||||
cfg.APIPort = GetAPIPort()
|
||||
cfg.MQPort = GetMQPort()
|
||||
cfg.GRPCHost = GetGRPCHost()
|
||||
cfg.GRPCPort = GetGRPCPort()
|
||||
cfg.GRPCConnString = GetGRPCConnString()
|
||||
cfg.MasterKey = "(hidden)"
|
||||
cfg.DNSKey = "(hidden)"
|
||||
cfg.AllowedOrigin = GetAllowedOrigin()
|
||||
cfg.RestBackend = "off"
|
||||
cfg.NodeID = GetNodeID()
|
||||
cfg.CheckinInterval = GetCheckinInterval()
|
||||
cfg.ServerCheckinInterval = GetServerCheckinInterval()
|
||||
cfg.MQPort = GetMQPort()
|
||||
if IsRestBackend() {
|
||||
cfg.RestBackend = "on"
|
||||
}
|
||||
|
@ -68,10 +72,6 @@ func GetServerConfig() config.ServerConfig {
|
|||
if DisableRemoteIPCheck() {
|
||||
cfg.DisableRemoteIPCheck = "on"
|
||||
}
|
||||
cfg.DisableDefaultNet = "off"
|
||||
if DisableDefaultNet() {
|
||||
cfg.DisableRemoteIPCheck = "on"
|
||||
}
|
||||
cfg.Database = GetDB()
|
||||
cfg.Platform = GetPlatform()
|
||||
cfg.Version = GetVersion()
|
||||
|
@ -90,8 +90,10 @@ func GetServerConfig() config.ServerConfig {
|
|||
cfg.Debug = GetDebug()
|
||||
cfg.Telemetry = Telemetry()
|
||||
cfg.ManageIPTables = ManageIPTables()
|
||||
cfg.CommsCIDR = GetCommsCIDR()
|
||||
services := strings.Join(GetPortForwardServiceList(), ",")
|
||||
cfg.PortForwardServices = services
|
||||
cfg.CommsID = GetCommsCIDR()
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
@ -177,17 +179,6 @@ func GetAPIPort() string {
|
|||
return apiport
|
||||
}
|
||||
|
||||
// GetCheckinInterval - get check in interval for nodes
|
||||
func GetCheckinInterval() string {
|
||||
seconds := "15"
|
||||
if os.Getenv("CHECKIN_INTERVAL") != "" {
|
||||
seconds = os.Getenv("CHECKIN_INTERVAL")
|
||||
} else if config.Config.Server.CheckinInterval != "" {
|
||||
seconds = config.Config.Server.CheckinInterval
|
||||
}
|
||||
return seconds
|
||||
}
|
||||
|
||||
// GetDefaultNodeLimit - get node limit if one is set
|
||||
func GetDefaultNodeLimit() int32 {
|
||||
var limit int32
|
||||
|
@ -208,6 +199,8 @@ func GetGRPCConnString() string {
|
|||
conn = os.Getenv("SERVER_GRPC_CONN_STRING")
|
||||
} else if config.Config.Server.GRPCConnString != "" {
|
||||
conn = config.Config.Server.GRPCConnString
|
||||
} else {
|
||||
conn = GetGRPCHost() + ":" + GetGRPCPort()
|
||||
}
|
||||
return conn
|
||||
}
|
||||
|
@ -252,6 +245,42 @@ func GetGRPCPort() string {
|
|||
return grpcport
|
||||
}
|
||||
|
||||
// GetMQPort - gets the mq port
|
||||
func GetMQPort() string {
|
||||
mqport := "1883"
|
||||
if os.Getenv("MQ_PORT") != "" {
|
||||
mqport = os.Getenv("MQ_PORT")
|
||||
} else if config.Config.Server.MQPort != "" {
|
||||
mqport = config.Config.Server.MQPort
|
||||
}
|
||||
return mqport
|
||||
}
|
||||
|
||||
// GetGRPCPort - gets the grpc port
|
||||
func GetCommsCIDR() string {
|
||||
netrange := "172.242.0.0/16"
|
||||
if os.Getenv("COMMS_CIDR") != "" {
|
||||
netrange = os.Getenv("COMMS_CIDR")
|
||||
} else if config.Config.Server.CommsCIDR != "" {
|
||||
netrange = config.Config.Server.CommsCIDR
|
||||
}
|
||||
_, _, err := net.ParseCIDR(netrange)
|
||||
if err == nil {
|
||||
return netrange
|
||||
}
|
||||
return "172.242.0.0/16"
|
||||
}
|
||||
|
||||
// GetCommsID - gets the grpc port
|
||||
func GetCommsID() string {
|
||||
return commsID
|
||||
}
|
||||
|
||||
// SetCommsID - sets the commsID
|
||||
func SetCommsID(newCommsID string) {
|
||||
commsID = newCommsID
|
||||
}
|
||||
|
||||
// GetMessageQueueEndpoint - gets the message queue endpoint
|
||||
func GetMessageQueueEndpoint() string {
|
||||
host, _ := GetPublicIP()
|
||||
|
@ -266,7 +295,7 @@ func GetMessageQueueEndpoint() string {
|
|||
|
||||
// GetMasterKey - gets the configured master key of server
|
||||
func GetMasterKey() string {
|
||||
key := "secretkey"
|
||||
key := ""
|
||||
if os.Getenv("MASTER_KEY") != "" {
|
||||
key = os.Getenv("MASTER_KEY")
|
||||
} else if config.Config.Server.MasterKey != "" {
|
||||
|
@ -415,8 +444,8 @@ func IsGRPCSSL() bool {
|
|||
if os.Getenv("GRPC_SSL") == "on" {
|
||||
isssl = true
|
||||
}
|
||||
} else if config.Config.Server.DNSMode != "" {
|
||||
if config.Config.Server.DNSMode == "on" {
|
||||
} else if config.Config.Server.GRPCSSL != "" {
|
||||
if config.Config.Server.GRPCSSL == "on" {
|
||||
isssl = true
|
||||
}
|
||||
}
|
||||
|
@ -438,21 +467,6 @@ func DisableRemoteIPCheck() bool {
|
|||
return disabled
|
||||
}
|
||||
|
||||
// DisableDefaultNet - disable default net
|
||||
func DisableDefaultNet() bool {
|
||||
disabled := false
|
||||
if os.Getenv("DISABLE_DEFAULT_NET") != "" {
|
||||
if os.Getenv("DISABLE_DEFAULT_NET") == "on" {
|
||||
disabled = true
|
||||
}
|
||||
} else if config.Config.Server.DisableDefaultNet != "" {
|
||||
if config.Config.Server.DisableDefaultNet == "on" {
|
||||
disabled = true
|
||||
}
|
||||
}
|
||||
return disabled
|
||||
}
|
||||
|
||||
// GetPublicIP - gets public ip
|
||||
func GetPublicIP() (string, error) {
|
||||
|
||||
|
@ -516,18 +530,7 @@ func GetSQLConn() string {
|
|||
return sqlconn
|
||||
}
|
||||
|
||||
// IsSplitDNS - checks if split dns is on
|
||||
func IsSplitDNS() bool {
|
||||
issplit := false
|
||||
if os.Getenv("IS_SPLIT_DNS") == "yes" {
|
||||
issplit = true
|
||||
} else if config.Config.Server.SplitDNS == "yes" {
|
||||
issplit = true
|
||||
}
|
||||
return issplit
|
||||
}
|
||||
|
||||
// IsSplitDNS - checks if split dns is on
|
||||
// IsHostNetwork - checks if running on host network
|
||||
func IsHostNetwork() bool {
|
||||
ishost := false
|
||||
if os.Getenv("HOST_NETWORK") == "on" {
|
||||
|
@ -541,15 +544,25 @@ func IsHostNetwork() bool {
|
|||
// GetNodeID - gets the node id
|
||||
func GetNodeID() string {
|
||||
var id string
|
||||
var err error
|
||||
// id = getMacAddr()
|
||||
if os.Getenv("NODE_ID") != "" {
|
||||
id = os.Getenv("NODE_ID")
|
||||
} else if config.Config.Server.NodeID != "" {
|
||||
id = config.Config.Server.NodeID
|
||||
} else {
|
||||
id, err = os.Hostname()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
func SetNodeID(id string) {
|
||||
config.Config.Server.NodeID = id
|
||||
}
|
||||
|
||||
// GetServerCheckinInterval - gets the server check-in time
|
||||
func GetServerCheckinInterval() int64 {
|
||||
var t = int64(5)
|
||||
|
@ -592,22 +605,6 @@ func GetAzureTenant() string {
|
|||
return azureTenant
|
||||
}
|
||||
|
||||
// GetMacAddr - get's mac address
|
||||
func getMacAddr() string {
|
||||
ifas, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
var as []string
|
||||
for _, ifa := range ifas {
|
||||
a := ifa.HardwareAddr.String()
|
||||
if a != "" {
|
||||
as = append(as, a)
|
||||
}
|
||||
}
|
||||
return as[0]
|
||||
}
|
||||
|
||||
// GetRce - sees if Rce is enabled, off by default
|
||||
func GetRce() bool {
|
||||
return os.Getenv("RCE") == "on" || config.Config.Server.RCE == "on"
|
||||
|
|
|
@ -50,10 +50,12 @@ func portForwardServices() error {
|
|||
case "dns":
|
||||
err = iptablesPortForward("coredns", "53", "53", false)
|
||||
case "ssh":
|
||||
err = iptablesPortForward("127.0.0.1", "22", "22", true)
|
||||
err = iptablesPortForward("netmaker", "22", "22", false)
|
||||
default:
|
||||
params := strings.Split(service, ":")
|
||||
err = iptablesPortForward(params[0], params[1], params[2], true)
|
||||
if len(params) == 3 {
|
||||
err = iptablesPortForward(params[0], params[1], params[2], true)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -2,7 +2,6 @@ package serverctl
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
|
@ -10,10 +9,55 @@ import (
|
|||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/netclient/ncutils"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
)
|
||||
|
||||
const NETMAKER_BINARY_NAME = "netmaker"
|
||||
// COMMS_NETID - name of the comms network
|
||||
var COMMS_NETID string
|
||||
|
||||
const (
|
||||
// NETMAKER_BINARY_NAME - name of netmaker binary
|
||||
NETMAKER_BINARY_NAME = "netmaker"
|
||||
)
|
||||
|
||||
// InitializeCommsNetwork - Check if comms network exists (for MQ, DNS, SSH traffic), if not, create
|
||||
func InitializeCommsNetwork() error {
|
||||
|
||||
setCommsID()
|
||||
|
||||
_, err := logic.GetNetwork(COMMS_NETID)
|
||||
if err != nil {
|
||||
logger.Log(1, "comms net does not exist, creating")
|
||||
var network models.Network
|
||||
network.NetID = COMMS_NETID
|
||||
network.AddressRange = servercfg.GetCommsCIDR()
|
||||
network.IsPointToSite = "yes"
|
||||
network.DefaultUDPHolePunch = "yes"
|
||||
network.IsComms = "yes"
|
||||
return logic.CreateNetwork(network)
|
||||
}
|
||||
SyncServerNetwork(COMMS_NETID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetJWTSecret - sets the jwt secret on server startup
|
||||
func setCommsID() {
|
||||
currentid, idErr := logic.FetchCommsNetID()
|
||||
if idErr != nil {
|
||||
commsid := logic.RandomString(8)
|
||||
if err := logic.StoreCommsNetID(commsid); err != nil {
|
||||
logger.FatalLog("something went wrong when configuring comms id")
|
||||
}
|
||||
COMMS_NETID = commsid
|
||||
servercfg.SetCommsID(COMMS_NETID)
|
||||
return
|
||||
}
|
||||
COMMS_NETID = currentid
|
||||
servercfg.SetCommsID(COMMS_NETID)
|
||||
}
|
||||
|
||||
// InitServerNetclient - intializes the server netclient
|
||||
// 1. Check if config directory exists, if not attempt to make
|
||||
|
@ -34,9 +78,7 @@ func InitServerNetclient() error {
|
|||
var currentServerNode, nodeErr = logic.GetNetworkServerLocal(network.NetID)
|
||||
if nodeErr == nil {
|
||||
if err = logic.ServerPull(¤tServerNode, true); err != nil {
|
||||
logger.Log(1, fmt.Sprintf("failed pull for network %s, on server node %s",
|
||||
network.NetID,
|
||||
currentServerNode.ID))
|
||||
logger.Log(1, "failed pull for network", network.NetID, ", on server node", currentServerNode.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue