Browse Source

adding dns stuff

afeiszli 4 years ago
parent
commit
9db5d43304

+ 11 - 5
Dockerfile

@@ -1,6 +1,6 @@
 #first stage - builder
 
-FROM golang:1.14-stretch as builder
+FROM golang:latest as builder
 
 COPY . /app
 
@@ -10,22 +10,28 @@ ENV GO111MODULE=auto
 
 RUN CGO_ENABLED=0 GOOS=linux go build -o app main.go
 
+WORKDIR /app/netclient
+
+ENV GO111MODULE=auto
+
+RUN CGO_ENABLED=0 GOOS=linux go build -o netclient main.go
 
 #second stage
 
-FROM alpine:latest
+FROM debian:latest
 
-WORKDIR /root/
+RUN apt-get update && apt-get -y install systemd procps
 
-RUN apk add --no-cache tzdata
+WORKDIR /root/
 
 COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
 
 COPY --from=builder /app .
 COPY --from=builder /app/config config
+COPY --from=builder /app/netclient netclient
 
 EXPOSE 8081
 EXPOSE 50051
 
-CMD ["./app", "--clientmode=off"]
+CMD ["./app"]
 

+ 16 - 12
config/config.go

@@ -15,7 +15,7 @@ import (
 //setting dev by default
 func getEnv() string {
 
-  env := os.Getenv("APP_ENV")
+  env := os.Getenv("NETMAKER_ENV")
 
   if len(env) == 0 {
     return "dev"
@@ -35,16 +35,17 @@ type EnvironmentConfig struct {
 
 // ServerConfig :
 type ServerConfig struct {
-  Host   string  `yaml:"host"`
-  ApiPort   string `yaml:"apiport"`
-  GrpcPort   string `yaml:"grpcport"`
+  APIHost   string  `yaml:"apihost"`
+  APIPort   string `yaml:"apiport"`
+  GRPCHost   string `yaml:"grpchost"`
+  GRPCPort   string `yaml:"grpcport"`
   MasterKey	string `yaml:"masterkey"`
   AllowedOrigin	string `yaml:"allowedorigin"`
-  RestBackend bool `yaml:"restbackend"`
-  AgentBackend bool `yaml:"agentbackend"`
-  DefaultNetName string `yaml:"defaultnetname"`
-  DefaultNetRange string `yaml:"defaultnetrange"`
-  CreateDefault bool `yaml:"createdefault"`
+  RestBackend string `yaml:"restbackend"`
+  AgentBackend string `yaml:"agentbackend"`
+  ClientMode string `yaml:"clientmode"`
+  DNSMode string `yaml:"dnsmode"`
+  DisableRemoteIPCheck string `yaml:"disableremoteipcheck"`
 }
 
 type MongoConnConfig struct {
@@ -60,13 +61,16 @@ type MongoConnConfig struct {
 func readConfig() *EnvironmentConfig {
   file := fmt.Sprintf("config/environments/%s.yaml", getEnv())
   f, err := os.Open(file)
+  var cfg EnvironmentConfig
   if err != nil {
-    log.Fatal(err)
-    os.Exit(2)
+    //log.Fatal(err)
+    //os.Exit(2)
+    log.Println("Unable to open config file at config/environments/" + getEnv())
+    log.Println("Will proceed with defaults or enironment variables (no config file).")
+    return &cfg
   }
   defer f.Close()
 
-  var cfg EnvironmentConfig
   decoder := yaml.NewDecoder(f)
   err = decoder.Decode(&cfg)
   if err != nil {

+ 16 - 15
config/environments/dev.yaml

@@ -1,17 +1,18 @@
 server:
-  host: "localhost"
-  apiport: "8081"
-  grpcport: "50051"
-  masterkey: "secretkey"
-  allowedorigin: "*"
-  restbackend: true            
-  agentbackend: true
-  defaultnetname: "default"
-  defaultnetrange: "10.10.10.0/24"
-  createdefault: true
+  apihost: "" # defaults to 127.0.0.1 or remote ip (SERVER_HOST) if DisableRemoteIPCheck is not set to true. SERVER_API_HOST if set
+  apiport: "" # defaults to 8081 or HTTP_PORT (if set)
+  grpchost: "" # defaults to 127.0.0.1 or remote ip (SERVER_HOST) if DisableRemoteIPCheck is not set to true. SERVER_GRPC_HOST if set.
+  grpcport: "" # defaults to 50051 or GRPC_PORT (if set)
+  masterkey: "" # defaults to 'secretkey' or MASTER_KEY (if set)
+  allowedorigin: "" # defaults to '*' or CORS_ALLOWED_ORIGIN (if set)
+  restbackend: "" # defaults to "on" or REST_BACKEND (if set)
+  agentbackend: "" # defaults to "on" or AGENT_BACKEND (if set)
+  clientmode: "" # defaults to "on" or CLIENT_MODE (if set)
+  dnsmode: "" # defaults to "on" or DNS_MODE (if set)
+  disableremoteipcheck: "" # defaults to "false" or DISABLE_REMOTE_IP_CHECK (if set)
 mongoconn:
-  user: "mongoadmin"
-  pass: "mongopass"
-  host: "localhost"
-  port: "27017"
-  opts: '/?authSource=admin'
+  user: "" # defaults to "mongoadmin" or MONGO_ADMIN (if set)
+  pass: "" # defaults to "mongopass" or MONGO_PASS (if set)
+  host: "" # defaults to 127.0.0.1 or MONGO_HOST (if set)
+  port: "" # defaults to 27017 or MONGO_PORT (if set)
+  opts: '' # defaults to '/?authSource=admin' or MONGO_OPTS (if set)

+ 3 - 6
controllers/controller.go

@@ -2,6 +2,7 @@ package controller
 
 import (
     "github.com/gravitl/netmaker/mongoconn"
+    "github.com/gravitl/netmaker/servercfg"
     "os/signal"
     "os"
     "fmt"
@@ -10,7 +11,6 @@ import (
     "github.com/gorilla/mux"
     "github.com/gorilla/handlers"
     "sync"
-    "github.com/gravitl/netmaker/config"
 )
 
 
@@ -22,7 +22,7 @@ func HandleRESTRequests(wg *sync.WaitGroup) {
     // Currently allowed dev origin is all. Should change in prod
     // should consider analyzing the allowed methods further
     headersOk := handlers.AllowedHeaders([]string{"Access-Control-Allow-Origin", "X-Requested-With", "Content-Type", "authorization"})
-    originsOk := handlers.AllowedOrigins([]string{config.Config.Server.AllowedOrigin})
+    originsOk := handlers.AllowedOrigins([]string{servercfg.GetAllowedOrigin()})
     methodsOk := handlers.AllowedMethods([]string{"GET", "PUT", "POST", "DELETE"})
 
     nodeHandlers(r)
@@ -32,10 +32,7 @@ func HandleRESTRequests(wg *sync.WaitGroup) {
     fileHandlers(r)
     serverHandlers(r)
 
-		port := config.Config.Server.ApiPort
-	        if os.Getenv("API_PORT") != "" {
-			port = os.Getenv("API_PORT")
-		}
+		port := servercfg.GetAPIPort()
 
 		srv := &http.Server{Addr: ":" + port, Handler: handlers.CORS(originsOk, headersOk, methodsOk)(r)}
 		go func(){

+ 36 - 31
controllers/dnsHttpController.go

@@ -173,6 +173,40 @@ func GetCustomDNS(network string) ([]models.DNSEntry, error){
         return dns, err
 }
 
+func SetDNS() error {
+        hostfile := txeh.Hosts{}
+        var corefilestring string
+        networks, err := functions.ListNetworks()
+        if err != nil {
+                return err
+        }
+
+        for _, net := range networks {
+                corefilestring = corefilestring + net.NetID + " "
+                dns, err := GetDNS(net.NetID)
+                if err != nil {
+                        return err
+                }
+                for _, entry := range dns {
+                        hostfile.AddHost(entry.Address, entry.Name+"."+entry.Network)
+                        if err != nil {
+                                return err
+                        }
+                }
+        }
+        if corefilestring == "" {
+                corefilestring = "example.com"
+        }
+
+        err = hostfile.SaveAs("./config/dnsconfig/netmaker.hosts")
+        if err != nil {
+                return err
+        }
+        err = functions.SetCorefile(corefilestring)
+
+        return err
+}
+
 func GetDNSEntryNum(domain string, network string) (int, error){
 
         num := 0
@@ -406,43 +440,14 @@ func pushDNS(w http.ResponseWriter, r *http.Request) {
         // Set header
         w.Header().Set("Content-Type", "application/json")
 
-        err := WriteHosts()
+        err := SetDNS()
 
         if err != nil {
                 returnErrorResponse(w, r, formatError(err, "internal"))
                 return
 	}
-        json.NewEncoder(w).Encode("DNS Pushed to CoreDNS")
-}
 
-
-func WriteHosts() error {
-	//hostfile, err := txeh.NewHostsDefault()
-	hostfile := txeh.Hosts{}
-	/*
-	if err != nil {
-                return err
-        }
-	*/
-	networks, err := functions.ListNetworks()
-        if err != nil {
-                return err
-        }
-
-	for _, net := range networks {
-		dns, err := GetDNS(net.NetID)
-		if err != nil {
-			return err
-		}
-		for _, entry := range dns {
-			hostfile.AddHost(entry.Address, entry.Name+"."+entry.Network)
-			if err != nil {
-				return err
-	                }
-		}
-	}
-	err = hostfile.SaveAs("./config/netmaker.hosts")
-	return err
+        json.NewEncoder(w).Encode("DNS Pushed to CoreDNS")
 }
 
 func ValidateDNSCreate(entry models.DNSEntry) error {

+ 3 - 5
controllers/networkHttpController.go

@@ -9,9 +9,8 @@ import (
 	"net/http"
 	"strings"
 	"time"
-	"os"
 	"github.com/gorilla/mux"
-	"github.com/gravitl/netmaker/config"
+	"github.com/gravitl/netmaker/servercfg"
 	"github.com/gravitl/netmaker/functions"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/mongoconn"
@@ -83,7 +82,7 @@ func securityCheck(next http.Handler) http.HandlerFunc {
 
 //Consider a more secure way of setting master key
 func authenticateMaster(tokenString string) bool {
-	if tokenString == config.Config.Server.MasterKey  || (tokenString == os.Getenv("MASTER_KEY") && tokenString != "") {
+	if tokenString == servercfg.GetMasterKey() {
 		return true
 	}
 	return false
@@ -593,7 +592,6 @@ func createAccessKey(w http.ResponseWriter, r *http.Request) {
 	if accesskey.Uses == 0 {
 		accesskey.Uses = 1
 	}
-	_, gconf, err := functions.GetGlobalConfig()
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
@@ -605,7 +603,7 @@ func createAccessKey(w http.ResponseWriter, r *http.Request) {
 	}
 
 	netID := params["networkname"]
-	address := gconf.ServerGRPC + gconf.PortGRPC
+	address := servercfg.GetGRPCHost() + ":" + servercfg.GetGRPCPort()
 
 	accessstringdec := address + "|" + netID + "|" + accesskey.Value + "|" + privAddr
 	accesskey.AccessString = base64.StdEncoding.EncodeToString([]byte(accessstringdec))

+ 15 - 2
controllers/serverHttpController.go

@@ -3,7 +3,7 @@ package controller
 import (
     "github.com/gravitl/netmaker/models"
     "github.com/gravitl/netmaker/serverctl"
-    "github.com/gravitl/netmaker/config"
+    "github.com/gravitl/netmaker/servercfg"
     "encoding/json"
     "strings"
     "net/http"
@@ -12,6 +12,7 @@ import (
 
 func serverHandlers(r *mux.Router) {
     r.HandleFunc("/api/server/addnetwork/{network}", securityCheckServer(http.HandlerFunc(addNetwork))).Methods("POST")
+    r.HandleFunc("/api/server/getconfig", securityCheckServer(http.HandlerFunc(getConfig))).Methods("GET")
     r.HandleFunc("/api/server/removenetwork/{network}", securityCheckServer(http.HandlerFunc(removeNetwork))).Methods("DELETE")
 }
 
@@ -49,7 +50,7 @@ func securityCheckServer(next http.Handler) http.HandlerFunc {
 }
 //Consider a more secure way of setting master key
 func authenticateMasterServer(tokenString string) bool {
-    if tokenString == config.Config.Server.MasterKey {
+    if tokenString == servercfg.GetMasterKey() {
         return true
     }
     return false
@@ -72,6 +73,18 @@ func removeNetwork(w http.ResponseWriter, r *http.Request) {
         json.NewEncoder(w).Encode("Server removed from network " + params["network"])
 }
 
+func getConfig(w http.ResponseWriter, r *http.Request) {
+        // Set header
+        w.Header().Set("Content-Type", "application/json")
+
+        // get params
+
+        scfg := servercfg.GetConfig()
+
+        w.WriteHeader(http.StatusOK)
+        json.NewEncoder(w).Encode(scfg)
+}
+
 func addNetwork(w http.ResponseWriter, r *http.Request) {
         // Set header
         w.Header().Set("Content-Type", "application/json")

+ 15 - 18
controllers/userHttpController.go

@@ -156,10 +156,7 @@ func authorizeUser(next http.Handler) http.HandlerFunc {
 		username, _, err := functions.VerifyUserToken(authToken)
 
 		if err != nil {
-			errorResponse = models.ErrorResponse{
-				Code: http.StatusUnauthorized, Message: "W1R3: Error Verifying Auth Token.",
-			}
-			returnErrorResponse(w, r, errorResponse)
+			returnErrorResponse(w, r, formatError(err, "internal"))
 			return
 		}
 
@@ -240,8 +237,8 @@ func getUser(w http.ResponseWriter, r *http.Request) {
 	user, err := GetUser(params["username"])
 
 	if err != nil {
-		mongoconn.GetError(err, w)
-		return
+                returnErrorResponse(w, r, formatError(err, "internal"))
+                return
 	}
 
 	json.NewEncoder(w).Encode(user)
@@ -304,14 +301,14 @@ func createAdmin(w http.ResponseWriter, r *http.Request) {
 
 	err = ValidateUser("create", admin)
 	if err != nil {
-		json.NewEncoder(w).Encode(err)
-		return
+                returnErrorResponse(w, r, formatError(err, "internal"))
+                return
 	}
 
 	admin, err = CreateUser(admin)
 	if err != nil {
-		json.NewEncoder(w).Encode(err)
-		return
+                returnErrorResponse(w, r, formatError(err, "internal"))
+                return
 	}
 
 	json.NewEncoder(w).Encode(admin)
@@ -379,8 +376,8 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
 	//start here
 	user, err := GetUser(params["username"])
 	if err != nil {
-		json.NewEncoder(w).Encode(err)
-		return
+                returnErrorResponse(w, r, formatError(err, "internal"))
+                return
 	}
 
 	var userchange models.User
@@ -388,8 +385,8 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
 	// we decode our body request params
 	err = json.NewDecoder(r.Body).Decode(&userchange)
 	if err != nil {
-		json.NewEncoder(w).Encode(err)
-		return
+                returnErrorResponse(w, r, formatError(err, "internal"))
+                return
 	}
 
 	userchange.IsAdmin = true
@@ -397,15 +394,15 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
 	err = ValidateUser("update", userchange)
 
 	if err != nil {
-		json.NewEncoder(w).Encode(err)
-		return
+                returnErrorResponse(w, r, formatError(err, "internal"))
+                return
 	}
 
 	user, err = UpdateUser(userchange, user)
 
 	if err != nil {
-		json.NewEncoder(w).Encode(err)
-		return
+                returnErrorResponse(w, r, formatError(err, "internal"))
+                return
 	}
 
 	json.NewEncoder(w).Encode(user)

+ 37 - 5
docker-compose.yml

@@ -1,5 +1,8 @@
-version: "3.3"
+version: "3.4"
 
+volumes:
+  dnsconfig:
+  driver: local
 services:
   mongodb:
     image: mongo:4.2
@@ -13,24 +16,53 @@ services:
       MONGO_INITDB_ROOT_USERNAME: mongoadmin
       MONGO_INITDB_ROOT_PASSWORD: mongopass
   netmaker:
+    privileged: true
     container_name: netmaker
+    build: netmaker
     depends_on:
       - mongodb
-    image: gravitl/netmaker:v0.2
+    image: gravitl/netmaker:v0.3
     ports:
       - "8081:8081"
       - "50051:50051"
+    volumes:
+      - ./:/local
+      - /etc/netclient:/etc/netclient
+      - dnsconfig:/root/config/dnsconfig
+      - /usr/bin/wg:/usr/bin/wg:ro
+      - /var/run/dbus/system_bus_socket:/var/run/dbus/system_bus_socket
+      - /run/systemd/system:/run/systemd/system
+      - /etc/systemd/system:/etc/systemd/system
+      - /sys/fs/cgroup:/sys/fs/cgroup
     environment:
-      MONGO_HOST: mongodb
+      MONGO_HOST: "127.0.0.1"
+    cap_add:
+      - NET_ADMIN
+      - SYS_MODULE
     restart: always
+    network_mode: host
   netmaker-ui:
     container_name: netmaker-ui
     depends_on:
       - netmaker
-    image: gravitl/netmaker-ui:v0.2
+    image: gravitl/netmaker-ui:v0.3
+    links:
+      - "netmaker:api"
     ports:
       - "80:80"
     environment:
-      BACKEND_URL: "http://localhost:8081"
+      BACKEND_URL: "http://3.236.149.180:8081"
+  coredns:
+    depends_on:
+      - netmaker 
+    image: coredns/coredns
+    command: -conf /root/dnsconfig/Corefile
+    container_name: coredns
+    restart: always
+    ports:
+      - "53:53/udp"
+    volumes:
+      - dnsconfig:/root/dnsconfig
 volumes:
   mongovol: {}
+  dnsconfig: {}

+ 7 - 43
functions/helpers.go

@@ -16,6 +16,7 @@ import (
 
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/mongoconn"
+	"github.com/gravitl/netmaker/servercfg"
 	"go.mongodb.org/mongo-driver/bson"
 	"go.mongodb.org/mongo-driver/bson/primitive"
 	"go.mongodb.org/mongo-driver/mongo"
@@ -38,22 +39,13 @@ func CreateServerToken(netID string) (string, error) {
 	accesskey.Name = GenKeyName()
 	accesskey.Value = GenKey()
 	accesskey.Uses = 1
-	_, gconf, errG := GetGlobalConfig()
-	if errG != nil {
-		return "", errG
-	}
-	address := "localhost" + gconf.PortGRPC
+	address := "127.0.0.1:" + servercfg.GetGRPCPort()
 
 	privAddr := ""
 	if *network.IsLocal {
 		privAddr = network.LocalRange
 	}
 
-	fmt.Println("Token details:")
-	fmt.Println("    grpc address + port: " + address)
-	fmt.Println("                network: " + netID)
-	fmt.Println("          private range: " + privAddr)
-
 	accessstringdec := address + "|" + netID + "|" + accesskey.Value + "|" + privAddr
 
 	accesskey.AccessString = base64.StdEncoding.EncodeToString([]byte(accessstringdec))
@@ -131,8 +123,6 @@ func NetworkExists(name string) (bool, error) {
 		if err == mongo.ErrNoDocuments {
 			return false, nil
 		}
-		fmt.Println("ERROR RETRIEVING GROUP!")
-		fmt.Println(err)
 	}
 	return true, err
 }
@@ -530,8 +520,11 @@ func UniqueAddress6(networkName string) (string, error) {
 
         var network models.Network
         network, err := GetParentNetwork(networkName)
-	dualstack := *network.IsDualStack
-	if !*network.IsDualStack {
+        if err != nil {
+                fmt.Println("Network Not Found")
+                return "", err
+        }
+	if network.IsDualStack == nil || *network.IsDualStack == false {
 		return "", nil
 	}
 
@@ -560,35 +553,6 @@ func UniqueAddress6(networkName string) (string, error) {
         return "W1R3: NO UNIQUE ADDRESSES AVAILABLE", err1
 }
 
-//pretty simple get
-func GetGlobalConfig() (bool, models.GlobalConfig, error) {
-
-	create := false
-
-	filter := bson.M{}
-
-	var globalconf models.GlobalConfig
-
-	collection := mongoconn.Client.Database("netmaker").Collection("config")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	err := collection.FindOne(ctx, filter).Decode(&globalconf)
-
-	defer cancel()
-
-	if err == mongo.ErrNoDocuments {
-		fmt.Println("Global config does not exist. Need to create.")
-		create = true
-		return create, globalconf, err
-	} else if err != nil {
-		fmt.Println(err)
-		fmt.Println("Could not get global config")
-		return create, globalconf, err
-	}
-	return create, globalconf, err
-}
-
 //generate an access key value
 func GenKey() string {
 

+ 3 - 4
functions/jwt.go

@@ -2,9 +2,8 @@ package functions
 
 import (
     "time"
-    "os"
-    "github.com/gravitl/netmaker/config"
     "github.com/gravitl/netmaker/models"
+    "github.com/gravitl/netmaker/servercfg"
     "github.com/dgrijalva/jwt-go"
 )
 
@@ -51,7 +50,7 @@ func CreateUserJWT(username string, isadmin bool) (response string, err error) {
 func VerifyUserToken(tokenString string) (username string, isadmin bool, err error) {
     claims := &models.UserClaims{}
 
-    if tokenString == config.Config.Server.MasterKey || (tokenString == os.Getenv("MASTER_KEY") && tokenString != "") {
+    if tokenString == servercfg.GetMasterKey() {
         return "masteradministrator", true, nil
     }
 
@@ -71,7 +70,7 @@ func VerifyToken(tokenString string) (macaddress string, network string, err err
 
     //this may be a stupid way of serving up a master key
     //TODO: look into a different method. Encryption?
-    if tokenString == config.Config.Server.MasterKey || (tokenString == os.Getenv("MASTER_KEY") && tokenString != "") {
+    if tokenString == servercfg.GetMasterKey() {
         return "mastermac", "", nil
     }
 

+ 51 - 0
functions/local.go

@@ -0,0 +1,51 @@
+package functions
+
+import (
+        "fmt"
+	"path/filepath"
+        "log"
+        "os"
+	"io/ioutil"
+)
+
+
+func FileExists(f string) bool {
+    info, err := os.Stat(f)
+    if os.IsNotExist(err) {
+        return false
+    }
+    return !info.IsDir()
+}
+
+func SetCorefile(domains string) error {
+	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
+	if err != nil {
+            return err
+	}
+	_, err = os.Stat(dir + "/config/dnsconfig")
+        if os.IsNotExist(err) {
+                os.Mkdir(dir +"/config/dnsconfig", 744)
+        } else if err != nil {
+                fmt.Println("couldnt find or create /config/dnsconfig")
+                return err
+        }
+
+		corefile := domains + ` {
+    hosts /root/dnsconfig/netmaker.hosts {
+	reload 15s
+	fallthrough	
+    }
+    forward . 8.8.8.8 8.8.4.4
+    log
+}
+`
+		corebytes := []byte(corefile)
+
+		err = ioutil.WriteFile(dir + "/config/dnsconfig/Corefile", corebytes, 0644)
+		if err != nil {
+			log.Println(err)
+			log.Println("")
+			return err
+		}
+	return err
+}

+ 68 - 59
grpc/node.pb.go

@@ -138,7 +138,8 @@ type Node struct {
 	Postchanges          string   `protobuf:"bytes,21,opt,name=postchanges,proto3" json:"postchanges,omitempty"`
 	Allowedips           string   `protobuf:"bytes,22,opt,name=allowedips,proto3" json:"allowedips,omitempty"`
 	Islocal              bool     `protobuf:"varint,23,opt,name=islocal,proto3" json:"islocal,omitempty"`
-	Localrange           string   `protobuf:"bytes,24,opt,name=localrange,proto3" json:"localrange,omitempty"`
+	Dnsoff               bool     `protobuf:"varint,24,opt,name=dnsoff,proto3" json:"dnsoff,omitempty"`
+	Localrange           string   `protobuf:"bytes,25,opt,name=localrange,proto3" json:"localrange,omitempty"`
 	XXX_NoUnkeyedLiteral struct{} `json:"-"`
 	XXX_unrecognized     []byte   `json:"-"`
 	XXX_sizecache        int32    `json:"-"`
@@ -330,6 +331,13 @@ func (m *Node) GetIslocal() bool {
 	return false
 }
 
+func (m *Node) GetDnsoff() bool {
+	if m != nil {
+		return m.Dnsoff
+	}
+	return false
+}
+
 func (m *Node) GetLocalrange() string {
 	if m != nil {
 		return m.Localrange
@@ -1034,62 +1042,63 @@ func init() {
 func init() { proto.RegisterFile("grpc/node.proto", fileDescriptor_d13bd996b67da4ef) }
 
 var fileDescriptor_d13bd996b67da4ef = []byte{
-	// 903 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0x5f, 0x6f, 0xe4, 0x34,
-	0x10, 0x57, 0xf7, 0xba, 0xdd, 0xed, 0x6c, 0xb7, 0xed, 0xb9, 0xdc, 0x61, 0xad, 0x50, 0xb5, 0x8a,
-	0x10, 0xea, 0x21, 0xda, 0x2d, 0x45, 0x42, 0xbc, 0x21, 0x71, 0x48, 0x27, 0x24, 0x38, 0x41, 0x10,
-	0x2f, 0xbc, 0xb9, 0xf1, 0x34, 0x17, 0x6d, 0x6a, 0xa7, 0xb1, 0xb7, 0xab, 0x7e, 0x00, 0xc4, 0x57,
-	0xe4, 0xc3, 0xf0, 0x80, 0x3c, 0x76, 0x36, 0x4e, 0x5a, 0xda, 0x83, 0x7b, 0x8b, 0x7f, 0x9e, 0x3f,
-	0x9e, 0x9f, 0x7f, 0x33, 0x0e, 0x1c, 0xe4, 0x75, 0x95, 0x2d, 0x94, 0x96, 0x78, 0x56, 0xd5, 0xda,
-	0x6a, 0xb6, 0xed, 0xbe, 0x13, 0x09, 0x7b, 0x3f, 0xea, 0xbc, 0x50, 0x29, 0xde, 0xac, 0xd0, 0x58,
-	0x76, 0x0c, 0x70, 0x2d, 0x32, 0x21, 0x65, 0x8d, 0xc6, 0xf0, 0xad, 0xf9, 0xd6, 0xc9, 0x6e, 0x1a,
-	0x21, 0x6c, 0x06, 0xe3, 0x4a, 0x18, 0xb3, 0xd6, 0xb5, 0xe4, 0x03, 0xda, 0xdd, 0xac, 0x19, 0x87,
-	0x91, 0x42, 0xbb, 0xd6, 0xf5, 0x92, 0x3f, 0xa3, 0xad, 0x66, 0x99, 0x7c, 0x09, 0xd3, 0x90, 0xc5,
-	0x54, 0x5a, 0x19, 0x64, 0x73, 0x98, 0x88, 0x2c, 0x43, 0x63, 0xac, 0x5e, 0xa2, 0x0a, 0x79, 0x62,
-	0x28, 0xf9, 0x6b, 0x08, 0xdb, 0x6f, 0xb5, 0x44, 0xb6, 0x0f, 0x83, 0x42, 0x06, 0x8b, 0x41, 0x21,
-	0x19, 0x83, 0x6d, 0x25, 0xae, 0x31, 0x64, 0xa7, 0x6f, 0x97, 0xb9, 0x39, 0x72, 0xc8, 0xdc, 0x9c,
-	0xf7, 0x18, 0xa0, 0x2c, 0x8c, 0x45, 0x55, 0xe9, 0xda, 0xf2, 0xed, 0xf9, 0xd6, 0xc9, 0x30, 0x8d,
-	0x10, 0xf6, 0x09, 0xec, 0x56, 0xab, 0xcb, 0xb2, 0xc8, 0x96, 0x78, 0xc7, 0x87, 0xe4, 0xdb, 0x02,
-	0xae, 0x5a, 0x54, 0xb2, 0xd2, 0x85, 0xb2, 0x7c, 0xc7, 0x57, 0xdb, 0xac, 0x7b, 0x4c, 0x8d, 0x1e,
-	0x65, 0x6a, 0xdc, 0x63, 0x6a, 0x0e, 0x13, 0xc7, 0x7e, 0xc3, 0xd6, 0xae, 0x2f, 0x3f, 0x82, 0xdc,
-	0xb9, 0x0a, 0x53, 0xa1, 0x92, 0x85, 0xca, 0x39, 0xcc, 0xb7, 0x4e, 0xc6, 0x69, 0x0b, 0xb0, 0x97,
-	0xb0, 0x53, 0x69, 0x63, 0x57, 0x15, 0x9f, 0x90, 0x6b, 0x58, 0x51, 0x4e, 0x6d, 0xac, 0xd4, 0x6b,
-	0xc5, 0xf7, 0x42, 0xce, 0xb0, 0x76, 0x11, 0x97, 0x88, 0x95, 0x28, 0x8b, 0x5b, 0xe4, 0x53, 0x22,
-	0xa2, 0x05, 0x5c, 0x35, 0x46, 0xdc, 0x62, 0xa6, 0xd5, 0x55, 0x91, 0xf3, 0x7d, 0x4a, 0x18, 0x21,
-	0xce, 0xdb, 0xdf, 0x8e, 0xe3, 0xe9, 0xc0, 0xf3, 0xb4, 0x01, 0xe8, 0xb4, 0xca, 0x62, 0x7d, 0x25,
-	0x32, 0xe4, 0x87, 0x7e, 0x77, 0x03, 0xb8, 0x6a, 0x4b, 0x61, 0x6c, 0xf6, 0x0e, 0xb3, 0x65, 0xa1,
-	0xf8, 0x73, 0x5f, 0x6d, 0x04, 0xb1, 0x04, 0xf6, 0xdc, 0xf2, 0x5a, 0xcb, 0xe2, 0xaa, 0x40, 0xc9,
-	0x19, 0x99, 0x74, 0x30, 0x76, 0x02, 0x07, 0xc1, 0x9c, 0x22, 0xdf, 0x8a, 0x92, 0x1f, 0x51, 0x15,
-	0x7d, 0x98, 0xa2, 0xe9, 0x4c, 0x94, 0xcd, 0xdd, 0x7c, 0x14, 0xa2, 0x45, 0x98, 0x3b, 0x93, 0x63,
-	0x26, 0x7b, 0x27, 0x54, 0x8e, 0x86, 0xbf, 0xf0, 0x67, 0x8a, 0x20, 0xc7, 0x88, 0x28, 0x4b, 0xbd,
-	0x46, 0x59, 0x54, 0x86, 0xbf, 0xf4, 0xf7, 0xdb, 0x22, 0x4e, 0x73, 0x85, 0xa1, 0x98, 0xfc, 0x63,
-	0xa2, 0xab, 0x59, 0x92, 0xe6, 0xdc, 0x47, 0xed, 0x02, 0x71, 0xee, 0x3d, 0x5b, 0x24, 0xf9, 0x63,
-	0x00, 0x07, 0xaf, 0xdd, 0x99, 0x7f, 0x68, 0x1b, 0x82, 0xc3, 0xc8, 0xac, 0x88, 0x4f, 0x92, 0xfa,
-	0x38, 0x6d, 0x96, 0xec, 0x33, 0xd8, 0x57, 0x88, 0xb2, 0x42, 0xac, 0x57, 0x95, 0x14, 0xd6, 0x2b,
-	0x7f, 0x9c, 0xf6, 0x50, 0xf6, 0x39, 0x1c, 0x3a, 0xc4, 0xdf, 0x57, 0xb0, 0x7c, 0x46, 0x96, 0xf7,
-	0xf0, 0x46, 0x7f, 0xd7, 0x68, 0x8c, 0xc8, 0x91, 0xda, 0x22, 0xe8, 0x2f, 0x40, 0x5d, 0xfd, 0x0d,
-	0xfb, 0xfa, 0xfb, 0x14, 0xa6, 0x2e, 0xe6, 0x12, 0xef, 0x42, 0xa2, 0x1d, 0xb2, 0xe8, 0x82, 0x8e,
-	0x07, 0x07, 0x48, 0x2c, 0xd1, 0x22, 0x75, 0xc8, 0x38, 0x8d, 0x90, 0xe4, 0xcf, 0x01, 0x4c, 0x7f,
-	0x46, 0xac, 0xcd, 0x86, 0x05, 0xca, 0x9a, 0x0b, 0x8b, 0x6b, 0x71, 0x17, 0x78, 0x68, 0x01, 0x77,
-	0xaf, 0xe1, 0xd3, 0x33, 0xeb, 0x27, 0x40, 0x07, 0xfb, 0x80, 0x7e, 0xfe, 0xff, 0x33, 0xa4, 0xaf,
-	0xb7, 0xd1, 0x03, 0x7a, 0x7b, 0xb4, 0xfb, 0x92, 0x05, 0x4c, 0x5f, 0xd7, 0x28, 0x2c, 0xba, 0x89,
-	0x97, 0xe2, 0x0d, 0x3b, 0x06, 0x1a, 0xcf, 0xc4, 0xc1, 0xe4, 0x02, 0xce, 0x68, 0x6e, 0xd3, 0xa6,
-	0x1f, 0xdb, 0x3d, 0x07, 0xf3, 0x3e, 0x0e, 0xbf, 0xd1, 0xad, 0xfc, 0x87, 0x0c, 0xb1, 0xc3, 0xd3,
-	0x19, 0xde, 0xc0, 0x24, 0x45, 0x21, 0xdb, 0xf8, 0x8f, 0x3f, 0x24, 0xd1, 0x63, 0x31, 0xe8, 0x3e,
-	0x16, 0xa7, 0x71, 0xa0, 0xa7, 0xf3, 0xfe, 0x02, 0xd3, 0xef, 0x49, 0x4f, 0xef, 0x9b, 0xd9, 0x89,
-	0xdf, 0xa7, 0x7a, 0xdb, 0xbe, 0x23, 0x31, 0x94, 0xbc, 0xea, 0x86, 0x34, 0xff, 0xde, 0x9d, 0xae,
-	0xea, 0x37, 0x68, 0x83, 0x8a, 0x3f, 0xa4, 0xea, 0x6f, 0xe2, 0x40, 0x86, 0xbd, 0x82, 0xa1, 0xeb,
-	0x6d, 0x13, 0xca, 0x3e, 0xf2, 0x65, 0x77, 0xba, 0x25, 0xf5, 0x16, 0xc9, 0x17, 0x00, 0x9b, 0x69,
-	0xf2, 0xf4, 0xbd, 0xfe, 0x14, 0x59, 0x1b, 0xf6, 0xed, 0x66, 0xa8, 0xd6, 0x21, 0x6a, 0x70, 0x7c,
-	0xe1, 0x1d, 0x7b, 0x63, 0x2a, 0xed, 0x5b, 0x5f, 0xfc, 0x3d, 0x80, 0x89, 0x8b, 0xfe, 0x2b, 0xd6,
-	0xb7, 0x45, 0x86, 0xec, 0x1c, 0x86, 0xf4, 0xd2, 0x33, 0xe6, 0x03, 0xc4, 0x3f, 0x17, 0xb3, 0xa3,
-	0x0e, 0x16, 0x7a, 0xfe, 0x6b, 0x80, 0x56, 0xca, 0x2c, 0x98, 0x74, 0xba, 0x61, 0xf6, 0x00, 0x68,
-	0xd8, 0x39, 0x8c, 0x1b, 0x99, 0xb0, 0xe7, 0xde, 0x20, 0xd2, 0xdf, 0xec, 0x1e, 0x64, 0x5c, 0xa6,
-	0x56, 0xd2, 0x4d, 0xa6, 0x4e, 0x57, 0xcc, 0x1e, 0x00, 0xc9, 0xaf, 0x95, 0x43, 0xe3, 0xd7, 0xd1,
-	0xdc, 0xec, 0x01, 0xd0, 0xb0, 0x0b, 0x18, 0x37, 0x57, 0xda, 0x9c, 0x30, 0xd2, 0xca, 0xec, 0x1e,
-	0x64, 0xce, 0xb7, 0xd8, 0x29, 0x8c, 0x02, 0xe7, 0xec, 0xb0, 0x77, 0x05, 0x37, 0xb3, 0x3e, 0x62,
-	0xbe, 0x5b, 0xfc, 0x7e, 0x9a, 0x6b, 0x9d, 0x97, 0x78, 0x96, 0xeb, 0x52, 0xa8, 0xfc, 0x4c, 0xd7,
-	0xf9, 0x82, 0xfe, 0xef, 0x2e, 0x57, 0x57, 0x0b, 0x7b, 0x57, 0xa1, 0x59, 0x2c, 0x95, 0x5e, 0x2b,
-	0xfa, 0xf3, 0xab, 0x2e, 0x2f, 0x77, 0x68, 0xf3, 0xab, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x44,
-	0xc2, 0xe7, 0x07, 0x0f, 0x0a, 0x00, 0x00,
+	// 915 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0x5f, 0x6f, 0x23, 0x35,
+	0x10, 0x57, 0x72, 0x4d, 0x93, 0x4e, 0x9a, 0xb6, 0xe7, 0x72, 0x87, 0x89, 0x50, 0x15, 0xad, 0x10,
+	0xea, 0x21, 0xda, 0x94, 0x22, 0x21, 0xde, 0x90, 0x38, 0xa4, 0x13, 0x12, 0x9c, 0x60, 0x11, 0x2f,
+	0xbc, 0xb9, 0xeb, 0xc9, 0xde, 0x2a, 0x5b, 0x7b, 0xbb, 0xde, 0x34, 0xea, 0x07, 0x40, 0x7c, 0x5d,
+	0x3e, 0x00, 0x0f, 0xc8, 0x63, 0x6f, 0xd6, 0xbb, 0x0d, 0xed, 0x71, 0x7d, 0x5b, 0xff, 0x3c, 0x7f,
+	0x3c, 0xbf, 0xf9, 0x8d, 0xd7, 0x70, 0x98, 0x96, 0x45, 0x32, 0x57, 0x5a, 0xe2, 0x79, 0x51, 0xea,
+	0x4a, 0xb3, 0x1d, 0xfb, 0x1d, 0x49, 0xd8, 0xff, 0x49, 0xa7, 0x99, 0x8a, 0xf1, 0x66, 0x85, 0xa6,
+	0x62, 0x27, 0x00, 0xd7, 0x22, 0x11, 0x52, 0x96, 0x68, 0x0c, 0xef, 0xcd, 0x7a, 0xa7, 0x7b, 0x71,
+	0x80, 0xb0, 0x29, 0x8c, 0x0a, 0x61, 0xcc, 0x5a, 0x97, 0x92, 0xf7, 0x69, 0x77, 0xb3, 0x66, 0x1c,
+	0x86, 0x0a, 0xab, 0xb5, 0x2e, 0x97, 0xfc, 0x19, 0x6d, 0xd5, 0xcb, 0xe8, 0x2b, 0x98, 0xf8, 0x2c,
+	0xa6, 0xd0, 0xca, 0x20, 0x9b, 0xc1, 0x58, 0x24, 0x09, 0x1a, 0x53, 0xe9, 0x25, 0x2a, 0x9f, 0x27,
+	0x84, 0xa2, 0xbf, 0x07, 0xb0, 0xf3, 0x56, 0x4b, 0x64, 0x07, 0xd0, 0xcf, 0xa4, 0xb7, 0xe8, 0x67,
+	0x92, 0x31, 0xd8, 0x51, 0xe2, 0x1a, 0x7d, 0x76, 0xfa, 0xb6, 0x99, 0xeb, 0x23, 0xfb, 0xcc, 0xf5,
+	0x79, 0x4f, 0x00, 0xf2, 0xcc, 0x54, 0xa8, 0x0a, 0x5d, 0x56, 0x7c, 0x67, 0xd6, 0x3b, 0x1d, 0xc4,
+	0x01, 0xc2, 0x3e, 0x85, 0xbd, 0x62, 0x75, 0x95, 0x67, 0xc9, 0x12, 0xef, 0xf8, 0x80, 0x7c, 0x1b,
+	0xc0, 0x56, 0x8b, 0x4a, 0x16, 0x3a, 0x53, 0x15, 0xdf, 0x75, 0xd5, 0xd6, 0xeb, 0x0e, 0x53, 0xc3,
+	0x07, 0x99, 0x1a, 0x75, 0x98, 0x9a, 0xc1, 0xd8, 0xb2, 0x5f, 0xb3, 0xb5, 0xe7, 0xca, 0x0f, 0x20,
+	0x7b, 0xae, 0xcc, 0x14, 0xa8, 0x64, 0xa6, 0x52, 0x0e, 0xb3, 0xde, 0xe9, 0x28, 0x6e, 0x00, 0xf6,
+	0x12, 0x76, 0x0b, 0x6d, 0xaa, 0x55, 0xc1, 0xc7, 0xe4, 0xea, 0x57, 0x94, 0x53, 0x9b, 0x4a, 0xea,
+	0xb5, 0xe2, 0xfb, 0x3e, 0xa7, 0x5f, 0xdb, 0x88, 0x4b, 0xc4, 0x42, 0xe4, 0xd9, 0x2d, 0xf2, 0x09,
+	0x11, 0xd1, 0x00, 0xb6, 0x1a, 0x23, 0x6e, 0x31, 0xd1, 0x6a, 0x91, 0xa5, 0xfc, 0x80, 0x12, 0x06,
+	0x88, 0xf5, 0x76, 0xdd, 0xb1, 0x3c, 0x1d, 0x3a, 0x9e, 0x36, 0x00, 0x9d, 0x56, 0x55, 0x58, 0x2e,
+	0x44, 0x82, 0xfc, 0xc8, 0xed, 0x6e, 0x00, 0x5b, 0x6d, 0x2e, 0x4c, 0x95, 0xbc, 0xc3, 0x64, 0x99,
+	0x29, 0xfe, 0xdc, 0x55, 0x1b, 0x40, 0x2c, 0x82, 0x7d, 0xbb, 0xbc, 0xd6, 0x32, 0x5b, 0x64, 0x28,
+	0x39, 0x23, 0x93, 0x16, 0xc6, 0x4e, 0xe1, 0xd0, 0x9b, 0x53, 0xe4, 0x5b, 0x91, 0xf3, 0x63, 0xaa,
+	0xa2, 0x0b, 0x53, 0x34, 0x9d, 0x88, 0xbc, 0xee, 0xcd, 0x47, 0x3e, 0x5a, 0x80, 0xd9, 0x33, 0x59,
+	0x66, 0x92, 0x77, 0x42, 0xa5, 0x68, 0xf8, 0x0b, 0x77, 0xa6, 0x00, 0xb2, 0x8c, 0x88, 0x3c, 0xd7,
+	0x6b, 0x94, 0x59, 0x61, 0xf8, 0x4b, 0xd7, 0xdf, 0x06, 0xb1, 0x9a, 0xcb, 0x0c, 0xc5, 0xe4, 0x1f,
+	0x13, 0x5d, 0xf5, 0xd2, 0x76, 0x47, 0x2a, 0xa3, 0x17, 0x0b, 0xce, 0x69, 0xc3, 0xaf, 0x48, 0x8b,
+	0xd6, 0xa0, 0xb4, 0x09, 0xf8, 0x27, 0x2e, 0x62, 0x83, 0x44, 0x7f, 0xf6, 0xe1, 0xf0, 0xb5, 0xad,
+	0xe5, 0xc7, 0x66, 0x50, 0x38, 0x0c, 0xcd, 0x8a, 0x78, 0xa6, 0x11, 0x18, 0xc5, 0xf5, 0x92, 0x7d,
+	0x0e, 0x07, 0x0a, 0x51, 0x16, 0x88, 0xe5, 0xaa, 0x90, 0xa2, 0x72, 0x13, 0x31, 0x8a, 0x3b, 0x28,
+	0xfb, 0x02, 0x8e, 0x2c, 0xe2, 0xfa, 0xe8, 0x2d, 0x9f, 0x91, 0xe5, 0x3d, 0xbc, 0xd6, 0xe5, 0x35,
+	0x1a, 0x23, 0x52, 0xa4, 0x71, 0xf1, 0xba, 0xf4, 0x50, 0x5b, 0x97, 0x83, 0xae, 0x2e, 0x3f, 0x83,
+	0x89, 0x8d, 0xb9, 0xc4, 0x3b, 0x9f, 0x68, 0x97, 0x2c, 0xda, 0xa0, 0xe5, 0xc1, 0x02, 0x12, 0x73,
+	0xac, 0x90, 0x26, 0x67, 0x14, 0x07, 0x48, 0xf4, 0x57, 0x1f, 0x26, 0xbf, 0x20, 0x96, 0x66, 0xc3,
+	0x02, 0x65, 0x4d, 0x45, 0x85, 0x6b, 0x71, 0xe7, 0x79, 0x68, 0x00, 0xdb, 0x6f, 0xff, 0xe9, 0x98,
+	0x75, 0x37, 0x43, 0x0b, 0x7b, 0xc2, 0x9c, 0x7f, 0xf8, 0xdd, 0xd2, 0xd5, 0xe1, 0x70, 0x8b, 0x0e,
+	0x1f, 0x9c, 0xca, 0x68, 0x0e, 0x93, 0xd7, 0x25, 0x8a, 0x0a, 0xed, 0x4d, 0x18, 0xe3, 0x0d, 0x3b,
+	0x01, 0xba, 0xb6, 0x89, 0x83, 0xf1, 0x25, 0x9c, 0xd3, 0x7d, 0x4e, 0x9b, 0xee, 0x3a, 0xef, 0x38,
+	0x98, 0xf7, 0x71, 0xf8, 0x9d, 0xba, 0xf2, 0x3f, 0x32, 0x84, 0x0e, 0x8f, 0x67, 0x78, 0x03, 0xe3,
+	0x18, 0x85, 0x6c, 0xe2, 0x3f, 0xfc, 0x83, 0x09, 0x7e, 0x22, 0xfd, 0xf6, 0x4f, 0xe4, 0x2c, 0x0c,
+	0xf4, 0x78, 0xde, 0x5f, 0x61, 0xf2, 0x03, 0xe9, 0xe9, 0x7d, 0x33, 0x5b, 0xf1, 0xbb, 0x54, 0x6f,
+	0x9b, 0xff, 0x4b, 0x08, 0x45, 0xaf, 0xda, 0x21, 0xcd, 0x7f, 0x4f, 0xa7, 0xad, 0xfa, 0x0d, 0x56,
+	0x5e, 0xc5, 0x4f, 0xa9, 0xfa, 0xdb, 0x30, 0x90, 0x61, 0xaf, 0x60, 0x60, 0x67, 0xdb, 0xf8, 0xb2,
+	0x8f, 0x5d, 0xd9, 0xad, 0x69, 0x89, 0x9d, 0x45, 0xf4, 0x25, 0xc0, 0xe6, 0x36, 0x79, 0xbc, 0xaf,
+	0x3f, 0x07, 0xd6, 0x86, 0x7d, 0xb7, 0xb9, 0x6c, 0x4b, 0x1f, 0xd5, 0x3b, 0xbe, 0x70, 0x8e, 0x9d,
+	0x6b, 0x2a, 0xee, 0x5a, 0x5f, 0xfe, 0xd3, 0x87, 0xb1, 0x8d, 0xfe, 0x1b, 0x96, 0xb7, 0x59, 0x82,
+	0xec, 0x02, 0x06, 0xf4, 0x02, 0x60, 0xcc, 0x05, 0x08, 0x1f, 0x1d, 0xd3, 0xe3, 0x16, 0xe6, 0x67,
+	0xfe, 0x1b, 0x80, 0x46, 0xca, 0xcc, 0x9b, 0xb4, 0xa6, 0x61, 0xba, 0x05, 0x34, 0xec, 0x02, 0x46,
+	0xb5, 0x4c, 0xd8, 0x73, 0x67, 0x10, 0xe8, 0x6f, 0x7a, 0x0f, 0x32, 0x36, 0x53, 0x23, 0xe9, 0x3a,
+	0x53, 0x6b, 0x2a, 0xa6, 0x5b, 0x40, 0xf2, 0x6b, 0xe4, 0x50, 0xfb, 0xb5, 0x34, 0x37, 0xdd, 0x02,
+	0x1a, 0x76, 0x09, 0xa3, 0xba, 0xa5, 0xf5, 0x09, 0x03, 0xad, 0x4c, 0xef, 0x41, 0xe6, 0xa2, 0xc7,
+	0xce, 0x60, 0xe8, 0x39, 0x67, 0x47, 0x9d, 0x16, 0xdc, 0x4c, 0xbb, 0x88, 0xf9, 0x7e, 0xfe, 0xc7,
+	0x59, 0xaa, 0x75, 0x9a, 0xe3, 0x79, 0xaa, 0x73, 0xa1, 0xd2, 0x73, 0x5d, 0xa6, 0x73, 0x7a, 0xf7,
+	0x5d, 0xad, 0x16, 0xf3, 0xea, 0xae, 0x40, 0x33, 0x5f, 0x2a, 0xbd, 0x56, 0xf4, 0x22, 0x2c, 0xae,
+	0xae, 0x76, 0x69, 0xf3, 0xeb, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x0e, 0xb4, 0x28, 0x5a, 0x27,
+	0x0a, 0x00, 0x00,
 }

+ 56 - 192
main.go

@@ -5,20 +5,11 @@ package main
 
 import (
     "log"
-    "flag"
-    "github.com/gravitl/netmaker/models"
     "github.com/gravitl/netmaker/controllers"
+    "github.com/gravitl/netmaker/servercfg"
     "github.com/gravitl/netmaker/serverctl"
-    "github.com/gravitl/netmaker/functions"
     "github.com/gravitl/netmaker/mongoconn"
-    "github.com/gravitl/netmaker/config"
-    "go.mongodb.org/mongo-driver/bson"
     "fmt"
-    "time"
-    "net/http"
-    "strings"
-    "errors"
-    "io/ioutil"
     "os"
     "os/exec"
     "net"
@@ -26,70 +17,82 @@ import (
     "strconv"
     "sync"
     "os/signal"
-    "go.mongodb.org/mongo-driver/mongo"
     service "github.com/gravitl/netmaker/controllers"
     nodepb "github.com/gravitl/netmaker/grpc"
     "google.golang.org/grpc"
 )
 
-var ServerGRPC string
-var PortGRPC string
-
 //Start MongoDB Connection and start API Request Handler
 func main() {
 
+	//Client Mode Prereq Check
+	if servercfg.IsClientMode() {
+		cmd := exec.Command("id", "-u")
+		output, err := cmd.Output()
 
-	var clientmode string
-	var defaultnet string
-	flag.StringVar(&clientmode, "clientmode", "on", "Have a client on the server")
-	flag.StringVar(&defaultnet, "defaultnet", "on", "Create a default network")
-	flag.Parse()
-	if clientmode == "on" {
-
-         cmd := exec.Command("id", "-u")
-         output, err := cmd.Output()
-
-         if err != nil {
-                 log.Fatal(err)
-         }
-         i, err := strconv.Atoi(string(output[:len(output)-1]))
-         if err != nil {
-                 log.Fatal(err)
-         }
-
-         if i != 0 {
-                 log.Fatal("To run in client mode requires root privileges. Either turn off client mode with the --clientmode=off flag, or run with sudo.")
-         }
+		if err != nil {
+			fmt.Println("Error running 'id -u' for prereq check. Please investigate or disable client mode.")
+			log.Fatal(err)
+		}
+		i, err := strconv.Atoi(string(output[:len(output)-1]))
+		if err != nil {
+                        fmt.Println("Error retrieving uid from 'id -u' for prereq check. Please investigate or disable client mode.")
+			log.Fatal(err)
+		}
+		if i != 0 {
+			log.Fatal("To run in client mode requires root privileges. Either disable client mode or run with sudo.")
+		}
 	}
 
-	log.Println("Server starting...")
+	//Start Mongodb
 	mongoconn.ConnectDatabase()
 
 	installserver := false
-	if !(defaultnet == "off") {
-	if config.Config.Server.CreateDefault {
-		created, err := createDefaultNetwork()
-		if err != nil {
-			fmt.Printf("Error creating default network: %v", err)
-		}
-		if created && clientmode != "off" {
-			installserver = true
-		}
+
+	//Create the default network (default: 10.10.10.0/24)
+	created, err := serverctl.CreateDefaultNetwork()
+	if err != nil {
+		fmt.Printf("Error creating default network: %v", err)
 	}
+
+	if created && servercfg.IsClientMode() {
+		installserver = true
 	}
+
+	//NOTE: Removed Check and Logic for DNS Mode
+	//Reasoning. DNS Logic is very small on server. Can run with little/no impact. Just sets a tiny config file.
+	//Real work is done by CoreDNS
+	//We can just not run CoreDNS. On Agent side is only necessary check for IsDNSMode, which we will pass.
+
 	var waitnetwork sync.WaitGroup
 
-	if config.Config.Server.AgentBackend {
+	//Run Agent Server
+	if servercfg.IsAgentBackend() {
+	        if !(servercfg.DisableRemoteIPCheck()) && servercfg.GetGRPCHost() == "127.0.0.1" {
+			err := servercfg.SetHost()
+			if err != nil {
+				fmt.Println("Unable to Set host. Exiting.")
+				log.Fatal(err)
+			}
+		}
 		waitnetwork.Add(1)
 		go runGRPC(&waitnetwork, installserver)
 	}
 
-	if config.Config.Server.RestBackend {
+	//Run Rest Server
+	if servercfg.IsRestBackend() {
+                if !servercfg.DisableRemoteIPCheck() && servercfg.GetAPIHost() == "127.0.0.1" {
+                        err := servercfg.SetHost()
+                        if err != nil {
+                                fmt.Println("Unable to Set host. Exiting.")
+                                log.Fatal(err)
+                        }
+                }
 		waitnetwork.Add(1)
 		controller.HandleRESTRequests(&waitnetwork)
 	}
-	if !config.Config.Server.RestBackend && !config.Config.Server.AgentBackend {
-		fmt.Println("Oops! No Server Mode selected. Nothing being served.")
+	if !servercfg.IsAgentBackend() && !servercfg.IsRestBackend() {
+		fmt.Println("Oops! No Server Mode selected. Nothing is being served! Set either Agent mode (AGENT_BACKEND) or Rest mode (REST_BACKEND) to 'true'.")
 	}
 	waitnetwork.Wait()
 	fmt.Println("Exiting now.")
@@ -105,38 +108,9 @@ func runGRPC(wg *sync.WaitGroup, installserver bool) {
         // Pipe flags to one another (log.LstdFLags = log.Ldate | log.Ltime)
         log.SetFlags(log.LstdFlags | log.Lshortfile)
 
-        // Start our listener, 50051 is the default gRPC port
-	grpcport := ":50051"
-	if config.Config.Server.GrpcPort != "" {
-		grpcport = ":" + config.Config.Server.GrpcPort
-	}
-        if os.Getenv("GRPC_PORT") != "" {
-		grpcport = ":" + os.Getenv("GRPC_PORT")
-        }
-	PortGRPC = grpcport
-	if os.Getenv("BACKEND_URL") == ""  {
-		if config.Config.Server.Host == "" {
-			ServerGRPC, _ = getPublicIP()
-		} else {
-			ServerGRPC = config.Config.Server.Host
-		}
-	} else {
-		ServerGRPC = os.Getenv("BACKEND_URL")
-	}
-	fmt.Println("GRPC Server set to: " + ServerGRPC)
-	fmt.Println("GRPC Port set to: " + PortGRPC)
-	var gconf models.GlobalConfig
-	gconf.ServerGRPC = ServerGRPC
-	gconf.PortGRPC = PortGRPC
-	gconf.Name = "netmaker"
-	err := setGlobalConfig(gconf)
+	grpcport := servercfg.GetGRPCPort()
 
-	if err != nil && err != mongo.ErrNoDocuments{
-	      log.Fatalf("Unable to set global config: %v", err)
-	}
-
-
-	listener, err := net.Listen("tcp", grpcport)
+	listener, err := net.Listen("tcp", ":"+grpcport)
         // Handle errors if any
         if err != nil {
                 log.Fatalf("Unable to listen on port" + grpcport + ": %v", err)
@@ -163,8 +137,8 @@ func runGRPC(wg *sync.WaitGroup, installserver bool) {
         fmt.Println("Agent Server succesfully started on port " + grpcport + " (gRPC)")
 
 	if installserver {
-			fmt.Println("Adding server to " + config.Config.Server.DefaultNetName)
-                        success, err := serverctl.AddNetwork(config.Config.Server.DefaultNetName)
+			fmt.Println("Adding server to default network")
+                        success, err := serverctl.AddNetwork("default")
                         if err != nil {
                                 fmt.Printf("Error adding to default network: %v", err)
 				fmt.Println("")
@@ -179,8 +153,6 @@ func runGRPC(wg *sync.WaitGroup, installserver bool) {
 	}
         fmt.Println("Setup complete. You are ready to begin using netmaker.")
 
-
-
         // Right way to stop the server using a SHUTDOWN HOOK
         // Create a channel to receive OS signals
         c := make(chan os.Signal)
@@ -202,113 +174,6 @@ func runGRPC(wg *sync.WaitGroup, installserver bool) {
         mongoconn.Client.Disconnect(context.TODO())
         fmt.Println("MongoDB connection closed.")
 }
-func setGlobalConfig(globalconf models.GlobalConfig) (error) {
-
-        collection := mongoconn.Client.Database("netmaker").Collection("config")
-        ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	create, _, err := functions.GetGlobalConfig()
-	if create {
-		_, err := collection.InsertOne(ctx, globalconf)
-		defer cancel()
-		if err != nil {
-			if err == mongo.ErrNoDocuments || strings.Contains(err.Error(), "no documents in result"){
-				return nil
-			} else {
-				return err
-			}
-		}
-	} else {
-		filter := bson.M{"name": "netmaker"}
-		update := bson.D{
-			{"$set", bson.D{
-				{"servergrpc", globalconf.ServerGRPC},
-				{"portgrpc", globalconf.PortGRPC},
-			}},
-		}
-		err := collection.FindOneAndUpdate(ctx, filter, update).Decode(&globalconf)
-                        if err == mongo.ErrNoDocuments {
-			//if err == mongo.ErrNoDocuments || strings.Contains(err.Error(), "no documents in result"){
-                                return nil
-                        }
-	}
-	return err
-}
-
-func createDefaultNetwork() (bool, error) {
-
-	iscreated := false
-	exists, err := functions.NetworkExists(config.Config.Server.DefaultNetName)
-
-	if exists || err != nil {
-		fmt.Println("Default network already exists")
-		fmt.Println("Skipping default network create")
-		return iscreated, err
-	} else {
-
-	var network models.Network
-
-	network.NetID = config.Config.Server.DefaultNetName
-	network.AddressRange = config.Config.Server.DefaultNetRange
-	network.DisplayName = config.Config.Server.DefaultNetName
-        network.SetDefaults()
-        network.SetNodesLastModified()
-        network.SetNetworkLastModified()
-        network.KeyUpdateTimeStamp = time.Now().Unix()
-	priv := false
-	network.IsLocal = &priv
-        network.KeyUpdateTimeStamp = time.Now().Unix()
-	allow := true
-	network.AllowManualSignUp = &allow
-
-	fmt.Println("Creating default network.")
-
-
-        collection := mongoconn.Client.Database("netmaker").Collection("networks")
-        ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-
-        // insert our network into the network table
-        _, err = collection.InsertOne(ctx, network)
-        defer cancel()
-
-	}
-	if err == nil {
-		iscreated = true
-	}
-	return iscreated, err
-
-
-}
-
-
-func getPublicIP() (string, error) {
-
-        iplist := []string{"https://ifconfig.me", "http://api.ipify.org", "http://ipinfo.io/ip"}
-        endpoint := ""
-        var err error
-            for _, ipserver := range iplist {
-                resp, err := http.Get(ipserver)
-                if err != nil {
-                        continue
-                }
-                defer resp.Body.Close()
-                if resp.StatusCode == http.StatusOK {
-                        bodyBytes, err := ioutil.ReadAll(resp.Body)
-                        if err != nil {
-                                continue
-                        }
-                        endpoint = string(bodyBytes)
-                        break
-                }
-
-        }
-        if err == nil && endpoint == "" {
-                err =  errors.New("Public Address Not Found.")
-        }
-        return endpoint, err
-}
-
 
 func authServerUnaryInterceptor() grpc.ServerOption {
 	return grpc.UnaryInterceptor(controller.AuthServerUnaryInterceptor)
@@ -316,4 +181,3 @@ func authServerUnaryInterceptor() grpc.ServerOption {
 func authServerStreamInterceptor() grpc.ServerOption {
         return grpc.StreamInterceptor(controller.AuthServerStreamInterceptor)
 }
-

+ 10 - 86
mongoconn/mongoconn.go

@@ -2,13 +2,10 @@ package mongoconn
 
 import (
 	"context"
-	"encoding/json"
 	"log"
-	"os"
-	"net/http"
 	"go.mongodb.org/mongo-driver/mongo"
 	"go.mongodb.org/mongo-driver/mongo/options"
-        "github.com/gravitl/netmaker/config"
+        "github.com/gravitl/netmaker/servercfg"
 )
 
 var Client *mongo.Client
@@ -21,53 +18,14 @@ var port string
 var opts string
 
 func setVars() {
-
-	//defaults
-	user = "admin"
-	pass = "password"
-	host = "localhost"
-	port = "27017"
-	opts = "/?authSource=admin"
-
-	//override with settings from config file
-	if config.Config.MongoConn.User != "" {
-		user = config.Config.MongoConn.User
-	}
-        if config.Config.MongoConn.Pass != "" {
-                pass = config.Config.MongoConn.Pass
-        }
-        if config.Config.MongoConn.Host != "" {
-                host = config.Config.MongoConn.Host
-        }
-        if config.Config.MongoConn.Port != "" {
-                port = config.Config.MongoConn.Port
-        }
-        if config.Config.MongoConn.Opts != "" {
-                opts = config.Config.MongoConn.Opts
-        }
-
-	//override with settings from env
-	if os.Getenv("MONGO_USER") != "" {
-		user = os.Getenv("MONGO_USER")
-	}
-        if os.Getenv("MONGO_PASS") != "" {
-                pass = os.Getenv("MONGO_PASS")
-        }
-        if os.Getenv("MONGO_HOST") != "" {
-                host = os.Getenv("MONGO_HOST")
-        }
-        if os.Getenv("MONGO_PORT") != "" {
-                port = os.Getenv("MONGO_PORT")
-        }
-        if os.Getenv("MONGO_OPTS") != "" {
-                opts = os.Getenv("MONGO_OPTS")
-        }
+	user = servercfg.GetMongoUser()
+	pass = servercfg.GetMongoPass()
+	host = servercfg.GetMongoHost()
+	port = servercfg.GetMongoPort()
+	opts = servercfg.GetMongoOpts()
 }
 
-//TODO: are we  even using  this besides at startup? Is it truely necessary?
-//TODO: Use config file instead of os.Getenv
 func ConnectDatabase() {
-    log.Println("Database connecting...")
     // Set client options
 
     setVars()
@@ -80,9 +38,11 @@ func ConnectDatabase() {
 						opts )
 
     // Connect to MongoDB
+    log.Println("Connecting to MongoDB at " + host + ":" + port + "...")
     client, err := mongo.Connect(context.TODO(), clientOptions)
     Client = client
     if err != nil {
+	log.Println("Error encountered connecting to MongoDB. Terminating.")
         log.Fatal(err)
     }
 
@@ -90,36 +50,14 @@ func ConnectDatabase() {
     err = Client.Ping(context.TODO(), nil)
 
     if err != nil {
+	log.Println("Error encountered pinging MongoDB. Terminating.")
         log.Fatal(err)
     }
 
     NodeDB = Client.Database("netmaker").Collection("nodes")
     NetworkDB = Client.Database("netmaker").Collection("networks")
 
-    log.Println("Database Connected.")
-}
-
-//TODO: IDK if we're using ConnectDB any more.... I think we're just using Client.Database
-//Review and see if this is necessary
-// ConnectDB : This is helper function to connect mongoDB
-func ConnectDB(db string, targetCollection string) *mongo.Collection {
-
-	// Set client options
-	//clientOptions := options.Client().ApplyURI("mongodb://mongoadmin:mongopassword@localhost:27017/?authSource=admin")
-	clientOptions := options.Client().ApplyURI("mongodb://" + os.Getenv("MONGO_USER") + ":" +
-	os.Getenv("MONGO_PASS") + "@" + os.Getenv("MONGO_HOST") + ":" + os.Getenv("MONGO_PORT") + os.Getenv("MONGO_OPTS") )
-
-	// Connect to MongoDB
-	client, err := mongo.Connect(context.TODO(), clientOptions)
-
-	if err != nil {
-		log.Fatal(err)
-	}
-
-	//collection := client.Database("go_rest_api").Collection("wg")
-	collection := client.Database(db).Collection(targetCollection)
-
-	return collection
+    log.Println("MongoDB Connected.")
 }
 
 // ErrorResponse : This is error model.
@@ -127,17 +65,3 @@ type ErrorResponse struct {
 	StatusCode   int    `json:"status"`
 	ErrorMessage string `json:"message"`
 }
-
-// GetError : This is helper function to prepare error model.
-func GetError(err error, w http.ResponseWriter) {
-
-	var response = ErrorResponse{
-		ErrorMessage: err.Error(),
-		StatusCode:   http.StatusInternalServerError,
-	}
-
-	message, _ := json.Marshal(response)
-
-	w.WriteHeader(response.StatusCode)
-	w.Write(message)
-}

+ 0 - 6
netclient/config/config.go

@@ -236,9 +236,3 @@ func ReadConfig(network string) (*ClientConfig, error) {
 	}
 	return &cfg, err
 }
-/*
-func init() {
-  Config = readConfig()
-}
-*/
-

+ 6 - 2
netclient/functions/common.go

@@ -72,7 +72,7 @@ func GetFreePort(rangestart int32) (int32, error){
         return portno, err
 }
 
-func Install(accesskey string, password string, server string, network string, noauto bool, accesstoken string,  inputname string, dnsoff bool) error {
+func Install(accesskey string, password string, server string, network string, noauto bool, accesstoken string,  inputname string, pubip string, dnsoff bool) error {
 
 	tserver := ""
 	tnetwork := ""
@@ -254,6 +254,9 @@ func Install(accesskey string, password string, server string, network string, n
 	}
        fmt.Println("     Local Address: " + localaddress)
 
+        if pubip != "" && pubip != "nopubip" {
+                endpoint = pubip
+        } else {
         if nodecfg.Endpoint == "" {
 		if islocal && localaddress != "" {
 			endpoint = localaddress
@@ -271,6 +274,7 @@ func Install(accesskey string, password string, server string, network string, n
                 endpoint = nodecfg.Endpoint
 		fmt.Println("Endpoint set in config. Setting to address: " + endpoint)
         }
+	}
        fmt.Println("     Endpoint: " + endpoint)
 
 
@@ -516,7 +520,7 @@ func getLocalIP(localrange string) (string, error) {
 
 func getPublicIP() (string, error) {
 
-	iplist := []string{"https://ifconfig.me", "http://api.ipify.org", "http://ipinfo.io/ip"}
+	iplist := []string{"http://ip.client.gravitl.com","https://ifconfig.me", "http://api.ipify.org", "http://ipinfo.io/ip"}
 	endpoint := ""
 	var err error
 	    for _, ipserver := range iplist {

+ 20 - 28
netclient/functions/local.go

@@ -140,40 +140,32 @@ WantedBy=timers.target
                 return err
         }
 	}
-        sysExec, err := exec.LookPath("systemctl")
+        //sysExec, err := exec.LookPath("systemctl")
 
-        cmdSysEnableService := &exec.Cmd {
+        cmdSysEnableService := exec.Command("systemctl", "enable", "[email protected]")/*&exec.Cmd {
                 Path: sysExec,
                 Args: []string{ sysExec, "enable", "[email protected]" },
                 Stdout: os.Stdout,
                 Stderr: os.Stdout,
-        }
-	/*
-        cmdSysStartService := &exec.Cmd {
-                Path: sysExec,
-                Args: []string{ sysExec, "start", "[email protected]"},
-                Stdout: os.Stdout,
-                Stderr: os.Stdout,
-        }
-	*/
-        cmdSysDaemonReload := &exec.Cmd {
+        }*/
+        cmdSysDaemonReload := exec.Command("systemctl", "daemon-reload")/*&exec.Cmd {
                 Path: sysExec,
                 Args: []string{ sysExec, "daemon-reload"},
                 Stdout: os.Stdout,
                 Stderr: os.Stdout,
-        }
-        cmdSysEnableTimer := &exec.Cmd {
+        }*/
+        cmdSysEnableTimer := exec.Command("systemctl", "enable", "netclient-"+network+".timer")/*&exec.Cmd {
                 Path: sysExec,
                 Args: []string{ sysExec, "enable", "netclient-"+network+".timer" },
                 Stdout: os.Stdout,
                 Stderr: os.Stdout,
-        }
-        cmdSysStartTimer := &exec.Cmd {
+        }*/
+        cmdSysStartTimer := exec.Command("systemctl", "start", "netclient-"+network+".timer")/*&exec.Cmd {
                 Path: sysExec,
 		Args: []string{ sysExec, "start", "netclient-"+network+".timer"},
                 Stdout: os.Stdout,
                 Stderr: os.Stdout,
-        }
+        }*/
 
         err = cmdSysEnableService.Run()
         if  err  !=  nil {
@@ -213,7 +205,7 @@ func isOnlyService(network string) (bool, error) {
 }
 
 func RemoveSystemDServices(network string) error {
-        sysExec, err := exec.LookPath("systemctl")
+        //sysExec, err := exec.LookPath("systemctl")
 
 
 	fullremove, err := isOnlyService(network)
@@ -221,36 +213,36 @@ func RemoveSystemDServices(network string) error {
 		fmt.Println(err)
 	}
 
-        cmdSysDisableService := &exec.Cmd {
+	cmdSysDisableService := exec.Command("systemctl","disable","[email protected]")/* &exec.Cmd {
                 Path: sysExec,
                 Args: []string{ sysExec, "disable", "[email protected]"},
                 Stdout: os.Stdout,
                 Stderr: os.Stdout,
-        }
-        cmdSysDaemonReload := &exec.Cmd {
+        }*/
+        cmdSysDaemonReload := exec.Command("systemctl","daemon-reload")/*&exec.Cmd {
                 Path: sysExec,
                 Args: []string{ sysExec, "daemon-reload"},
                 Stdout: os.Stdout,
                 Stderr: os.Stdout,
-        }
-        cmdSysResetFailed := &exec.Cmd {
+        }*/
+        cmdSysResetFailed := exec.Command("systemctl","reset-failed")/*&exec.Cmd {
                 Path: sysExec,
                 Args: []string{ sysExec, "reset-failed"},
                 Stdout: os.Stdout,
                 Stderr: os.Stdout,
-        }
-        cmdSysStopTimer := &exec.Cmd {
+        }*/
+        cmdSysStopTimer := exec.Command("systemctl", "stop", "netclient-"+network+".timer")/*&exec.Cmd {
                 Path: sysExec,
                 Args: []string{ sysExec, "stop", "netclient-"+network+".timer" },
                 Stdout: os.Stdout,
                 Stderr: os.Stdout,
-        }
-        cmdSysDisableTimer := &exec.Cmd {
+        }*/
+        cmdSysDisableTimer :=  exec.Command("systemctl", "disable", "netclient-"+network+".timer")/*&exec.Cmd {
                 Path: sysExec,
                 Args: []string{ sysExec, "disable", "netclient-"+network+".timer"},
                 Stdout: os.Stdout,
                 Stderr: os.Stdout,
-        }
+        }*/
 
         //err = cmdSysStopService.Run()
         if  err  !=  nil {

+ 3 - 2
netclient/main.go

@@ -39,8 +39,9 @@ func main() {
 	tname := flag.String("name", "noname", "give the node a name at runtime")
 	tserver := flag.String("s", "localhost:50051", "The location (including port) of the remote gRPC server.")
 	tnetwork := flag.String("n", "nonetwork", "The node network you are attempting to join.")
-	tnoauto := flag.Bool("na", false, "No auto mode. If true, netclient will not be installed as a system service and you will have to retrieve updates manually via checkin command.")
 	tdnsoff := flag.Bool("dnsoff", false, "No dns mode. If true, netclient will not alter system dns.")
+	tpublicip := flag.String("ip4", "nopubip", "The node network you are attempting to join.")
+	tnoauto := flag.Bool("na", false, "No auto mode. If true, netmclient will not be installed as a system service and you will have to retrieve updates manually via checkin command.")
 	tnoforward := flag.Bool("nf", false, "No Forward mode. If true, netclient will not check for IP forwarding. This may break functionality")
 	command := flag.String("c", "required", "The command to run")
 
@@ -109,7 +110,7 @@ func main() {
 			}
 
 			fmt.Println("Beginning agent installation.")
-			err := functions.Install(*taccesskey, *tpassword, *tserver, *tnetwork, *tnoauto, *taccesstoken, *tname, *tdnsoff)
+			err := functions.Install(*taccesskey, *tpassword, *tserver, *tnetwork, *tnoauto, *taccesstoken, *tname, *tpublicip, *tdnsoff)
 			if err != nil {
 				fmt.Println("Error encountered while installing.")
 				if !strings.Contains(err.Error(), "ALREADY_INSTALLED") {

+ 0 - 0
netclient-install.sh → scripts/netclient-install.sh


+ 0 - 0
netmaker-install-clientmode.sh → scripts/netmaker-install-clientmode.sh


+ 101 - 0
scripts/netmaker-install-local.sh

@@ -0,0 +1,101 @@
+#!/bin/sh
+set -x
+
+[ -z "$SERVER_DOMAIN" ] && echo "Need to set SERVER_DOMAIN (format: 1.2.3.4 or mybackend.com)" && exit 1;
+
+
+install() {
+
+docker volume create mongovol && docker run -d --name mongodb -v mongovol:/data/db -p 27017:27017 -e MONGO_INITDB_ROOT_USERNAME=mongoadmin -e MONGO_INITDB_ROOT_PASSWORD=mongopass mongo 
+
+echo "Giving Mongo Time to Start"
+sleep 10
+echo "Installing Netmaker API"
+
+mkdir -p /etc/netmaker/config/environments
+mkdir -p /etc/netmaker/config/dnsconfig
+cp ../netmaker /etc/netmaker/netmaker
+chmod +x /etc/netmaker/netmaker
+
+
+cat >/etc/netmaker/config/environments/dev.yaml<<EOL
+server:
+  host: "$SERVER_DOMAIN"
+  apiport: "8081"
+  grpcport: "50051"
+  masterkey: "secretkey"
+  allowedorigin: "*"
+  restbackend: true            
+  agentbackend: true
+  defaultnetname: "default"
+  defaultnetrange: "10.10.10.0/24"
+  createdefault: true
+mongoconn:
+  user: "mongoadmin"
+  pass: "mongopass"
+  host: "127.0.0.1"
+  port: "27017"
+  opts: '/?authSource=admin'
+EOL
+
+cat >/etc/netmaker/config/dnsconfig/Corefile<<EOL
+. {
+    hosts ./root/netmaker.hosts {
+	fallthrough	
+    }
+    forward . 8.8.8.8 8.8.4.4
+    log
+}
+EOL
+
+cat >/etc/systemd/system/netmaker.service<<EOL
+[Unit]
+Description=Netmaker Server
+After=network.target
+
+[Service]
+Type=simple
+Restart=on-failure
+
+WorkingDirectory=/etc/netmaker
+ExecStart=/etc/netmaker/netmaker
+
+[Install]
+WantedBy=multi-user.target
+EOL
+systemctl daemon-reload
+systemctl start netmaker.service
+sudo docker pull coredns/coredns
+sudo docker pull gravitl/netmaker-ui:v0.3
+
+systemctl stop systemd-resolved
+systemctl disable systemd-resolved
+echo "Running CoreDNS"
+sudo docker run -d --name coredns --restart=always --volume=/etc/netmaker/config/dnsconfig/:/root/ -p 53:53/udp coredns/coredns -conf /root/Corefile
+
+echo "Running UI"
+sudo docker run -d --name netmaker-ui -p 80:80 -e BACKEND_URL="http://$SERVER_DOMAIN:8081" gravitl/netmaker-ui:v0.3
+
+echo "Setup Complete"
+}
+
+cleanup() {
+sudo docker kill mongodb || true
+sudo docker rm mongodb || true
+sudo docker volume rm mongovol || true
+sudo docker kill coredns || true
+sudo docker rm coredns || true
+sudo docker kill netmaker-ui || true
+sudo docker rm netmaker-ui || true
+sudo netclient -c remove -n default || true
+sudo rm -rf /etc/systemd/system/netmaker.service || true
+sudo rm -rf /etc/netmaker || true
+sudo systemctl enable systemd-resolved
+sudo systemctl start systemd-resolved
+sleep 5
+sudo systemctl restart systemd-resolved
+}
+
+trap cleanup ERR
+cleanup
+install

+ 0 - 0
netmaker-server.sh → scripts/netmaker-server.sh


+ 12 - 0
scripts/uninstall-netclient.sh

@@ -0,0 +1,12 @@
+#!/bin/sh
+set -x
+
+echo "Starting."
+
+sudo netclient -c remove-all || true
+sudo rm -rf /usr/local/bin/netclient || true
+sudo rm -rf /etc/netclient|| true
+find  /etc/systemd/system/ -name 'netclient*' -exec rm {} \;
+sudo systemctl daemon-reload || true
+
+echo "Done."

+ 26 - 0
scripts/uninstall-netmaker.sh

@@ -0,0 +1,26 @@
+#!/bin/sh
+set -x
+
+echo "Starting."
+
+sudo docker kill mongodb || true
+sudo docker rm mongodb || true
+sudo docker volume rm mongovol || true
+sudo  docker volume rm `docker volume ls -q -f dangling=true` || true
+sudo docker kill coredns || true
+sudo docker rm coredns || true
+sudo docker kill netmaker-ui || true
+sudo docker rm netmaker-ui || true
+sudo netclient -c remove -n default || true
+sudo rm -rf /etc/systemd/system/netmaker.service || true
+sudo rm -rf /etc/netmaker || true
+sudo rm -rf /usr/local/bin/netclient || true
+sudo rm -rf /etc/netclient|| true
+find  /etc/systemd/system/ -name 'netclient*' -exec rm {} \;
+sudo systemctl daemon-reload || true
+sudo systemctl enable systemd-resolved || true
+sudo systemctl start systemd-resolved || true
+sleep 5
+sudo systemctl restart systemd-resolved || true
+
+echo "Done."

+ 53 - 0
servercfg/mongoconf.go

@@ -0,0 +1,53 @@
+package servercfg
+
+import (
+        "github.com/gravitl/netmaker/config"
+        "os"
+)
+
+func GetMongoUser() string {
+	user := "mongoadmin"
+	if os.Getenv("MONGO_ADMIN") != "" {
+		user = os.Getenv("MONGO_ADMIN")
+	} else if  config.Config.MongoConn.User != "" {
+		user = config.Config.MongoConn.User
+	}
+	return user
+}
+func GetMongoPass() string {
+        pass := "mongopass"
+        if os.Getenv("MONGO_PASS") != "" {
+                pass = os.Getenv("MONGO_PASS")
+        } else if  config.Config.MongoConn.Pass != "" {
+                pass = config.Config.MongoConn.Pass
+        }
+        return pass
+}
+func GetMongoHost() string {
+        host := "127.0.0.1"
+        if os.Getenv("MONGO_HOST") != "" {
+                host = os.Getenv("MONGO_HOST")
+        } else if  config.Config.MongoConn.Host != "" {
+                host = config.Config.MongoConn.Host
+        }
+        return host
+}
+func GetMongoPort() string {
+        port := "27017"
+        if os.Getenv("MONGO_PORT") != "" {
+                port = os.Getenv("MONGO_PORT")
+        } else if  config.Config.MongoConn.Port != "" {
+                port = config.Config.MongoConn.Port
+        }
+        return port
+}
+func GetMongoOpts() string {
+        opts := "/?authSource=admin"
+        if os.Getenv("MONGO_OPTS") != "" {
+                opts = os.Getenv("MONGO_OPTS")
+        } else if  config.Config.MongoConn.Opts != "" {
+                opts = config.Config.MongoConn.Opts
+        }
+        return opts
+}
+

+ 199 - 0
servercfg/serverconf.go

@@ -0,0 +1,199 @@
+package servercfg
+
+import (
+        "github.com/gravitl/netmaker/config"
+	"net/http"
+	"io/ioutil"
+	"os"
+	"errors"
+)
+
+func SetHost() error {
+	remoteip, err := GetPublicIP()
+	if err != nil {
+		return err
+	}
+	os.Setenv("SERVER_HOST", remoteip)
+	return nil
+}
+func GetConfig() config.ServerConfig {
+	var cfg config.ServerConfig
+	cfg.APIHost = GetAPIHost()
+	cfg.APIPort = GetAPIPort()
+	cfg.GRPCHost = GetGRPCHost()
+	cfg.GRPCPort = GetGRPCPort()
+	cfg.MasterKey = "(hidden)"
+	cfg.AllowedOrigin = GetAllowedOrigin()
+	cfg.RestBackend = "off"
+	if IsRestBackend() {
+		cfg.RestBackend = "on"
+	}
+	cfg.AgentBackend = "off"
+        if IsAgentBackend() {
+                cfg.AgentBackend = "on"
+        }
+	cfg.ClientMode = "off"
+	if IsClientMode() {
+		cfg.ClientMode = "on"
+	}
+	cfg.DNSMode = "off"
+	if IsDNSMode() {
+	        cfg.DNSMode = "on"
+	}
+	cfg.DisableRemoteIPCheck = "off"
+	if DisableRemoteIPCheck() {
+		cfg.DisableRemoteIPCheck = "on"
+	}
+	return cfg
+}
+
+func GetAPIHost() string {
+        serverhost := "127.0.0.1"
+        if os.Getenv("SERVER_HTTP_HOST") != ""  {
+                serverhost = os.Getenv("SERVER_HTTP_HOST")
+        } else if config.Config.Server.APIHost != "" {
+		serverhost = config.Config.Server.APIHost
+        } else if os.Getenv("SERVER_HOST") != ""  {
+                serverhost = os.Getenv("SERVER_HOST")
+        }
+	return serverhost
+}
+func GetAPIPort() string {
+	apiport := "8081"
+	if os.Getenv("API_PORT") != "" {
+		apiport = os.Getenv("API_PORT")
+	} else if  config.Config.Server.APIPort != "" {
+		apiport = config.Config.Server.APIPort
+	}
+	return apiport
+}
+func GetGRPCHost() string {
+        serverhost := "127.0.0.1"
+        if os.Getenv("SERVER_GRPC_HOST") != ""  {
+                serverhost = os.Getenv("SERVER_GRPC_HOST")
+        } else if config.Config.Server.GRPCHost != "" {
+                serverhost = config.Config.Server.GRPCHost
+        } else if os.Getenv("SERVER_HOST") != ""  {
+                serverhost = os.Getenv("SERVER_HOST")
+        }
+        return serverhost
+}
+func GetGRPCPort() string {
+        grpcport := "50051"
+        if os.Getenv("GRPC_PORT") != "" {
+                grpcport = os.Getenv("GRPC_PORT")
+        } else if  config.Config.Server.GRPCPort != "" {
+                grpcport = config.Config.Server.GRPCPort
+        }
+        return grpcport
+}
+func GetMasterKey() string {
+        key := "secretkey"
+        if os.Getenv("MASTER_KEY") != "" {
+                key = os.Getenv("MASTER_KEY")
+        } else if  config.Config.Server.MasterKey != "" {
+                key = config.Config.Server.MasterKey
+        }
+        return key
+}
+func GetAllowedOrigin() string {
+        allowedorigin := "*"
+        if os.Getenv("CORS_ALLOWED_ORIGIN") != "" {
+                allowedorigin = os.Getenv("CORS_ALLOWED_ORIGIN")
+        } else if  config.Config.Server.AllowedOrigin != "" {
+                allowedorigin = config.Config.Server.AllowedOrigin
+        }
+        return allowedorigin
+}
+func IsRestBackend() bool {
+        isrest := true
+        if os.Getenv("REST_BACKEND") != "" {
+		if os.Getenv("REST_BACKEND") == "off" {
+			isrest = false
+		}
+	} else if config.Config.Server.RestBackend != "" {
+		if config.Config.Server.RestBackend == "off" {
+			isrest = false
+		}
+       }
+       return isrest
+}
+func IsAgentBackend() bool {
+        isagent := true
+        if os.Getenv("AGENT_BACKEND") != "" {
+                if os.Getenv("AGENT_BACKEND") == "off" {
+                        isagent = false
+                }
+        } else if config.Config.Server.AgentBackend != "" {
+                if config.Config.Server.AgentBackend == "off" {
+                        isagent = false
+                }
+       }
+       return isagent
+}
+func IsClientMode() bool {
+        isclient := true
+        if os.Getenv("CLIENT_MODE") != "" {
+                if os.Getenv("CLIENT_MODE") == "off" {
+                        isclient = false
+                }
+        } else if config.Config.Server.ClientMode != "" {
+                if config.Config.Server.ClientMode == "off" {
+                        isclient = false
+                }
+       }
+       return isclient
+}
+func IsDNSMode() bool {
+        isdns := true
+        if os.Getenv("DNS_MODE") != "" {
+                if os.Getenv("DNS_MODE") == "off" {
+                        isdns = false
+                }
+        } else if config.Config.Server.DNSMode != "" {
+                if config.Config.Server.DNSMode == "off" {
+                        isdns = false
+                }
+       }
+       return isdns
+}
+func DisableRemoteIPCheck() bool {
+        disabled := false
+        if os.Getenv("DISABLE_REMOTE_IP_CHECK") != "" {
+                if os.Getenv("DISABLE_REMOTE_IP_CHECK") == "on" {
+                        disabled = true
+                }
+        } else if config.Config.Server.DisableRemoteIPCheck != "" {
+                if config.Config.Server.DisableRemoteIPCheck == "on" {
+                        disabled= true
+                }
+       }
+       return disabled
+}
+func GetPublicIP() (string, error) {
+
+        endpoint := ""
+        var err error
+
+        iplist := []string{"http://ip.server.gravitl.com", "https://ifconfig.me", "http://api.ipify.org", "http://ipinfo.io/ip"}
+        for _, ipserver := range iplist {
+                resp, err := http.Get(ipserver)
+                if err != nil {
+                        continue
+                }
+                defer resp.Body.Close()
+                if resp.StatusCode == http.StatusOK {
+                        bodyBytes, err := ioutil.ReadAll(resp.Body)
+                        if err != nil {
+                                continue
+                        }
+                        endpoint = string(bodyBytes)
+                        break
+                }
+
+        }
+        if err == nil && endpoint == "" {
+                err =  errors.New("Public Address Not Found.")
+        }
+        return endpoint, err
+}

+ 104 - 8
serverctl/serverctl.go

@@ -2,17 +2,65 @@ package serverctl
 
 import (
         "fmt"
-  "github.com/gravitl/netmaker/functions"
+	"github.com/gravitl/netmaker/functions"
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/mongoconn"
+	"github.com/gravitl/netmaker/servercfg"
 	"io"
+	"time"
+	"context"
 	"errors"
-	"net/http"
         "os"
         "os/exec"
 )
 
+func CreateDefaultNetwork() (bool, error) {
 
-func DownloadNetclient() error {
+        fmt.Println("Creating default network...")
+
+        iscreated := false
+        exists, err := functions.NetworkExists("default")
+
+        if exists || err != nil {
+                fmt.Println("Default network already exists. Skipping...")
+                return iscreated, err
+        } else {
+
+        var network models.Network
+
+        network.NetID = "default"
+        network.AddressRange = "10.10.10.0/24"
+        network.DisplayName = "default"
+        network.SetDefaults()
+        network.SetNodesLastModified()
+        network.SetNetworkLastModified()
+        network.KeyUpdateTimeStamp = time.Now().Unix()
+        priv := false
+        network.IsLocal = &priv
+        network.KeyUpdateTimeStamp = time.Now().Unix()
+        allow := true
+        network.AllowManualSignUp = &allow
 
+        fmt.Println("Creating default network.")
+
+        collection := mongoconn.Client.Database("netmaker").Collection("networks")
+        ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+
+        // insert our network into the network table
+        _, err = collection.InsertOne(ctx, network)
+        defer cancel()
+
+        }
+        if err == nil {
+                iscreated = true
+        }
+        return iscreated, err
+
+
+}
+
+func DownloadNetclient() error {
+	/*
 	// Get the data
 	resp, err := http.Get("https://github.com/gravitl/netmaker/releases/download/latest/netclient")
 	if err != nil {
@@ -23,16 +71,58 @@ func DownloadNetclient() error {
 
 	// Create the file
 	out, err := os.Create("/etc/netclient/netclient")
+        */
+        if !FileExists("/etc/netclient/netclient") {
+		_, err := copy("./netclient/netclient", "/etc/netclient/netclient")
 	if err != nil {
                 fmt.Println("could not create /etc/netclient")
 		return err
 	}
-	defer out.Close()
+	}
+	//defer out.Close()
 
 	// Write the body to file
-	_, err = io.Copy(out, resp.Body)
-	return err
+	//_, err = io.Copy(out, resp.Body)
+	return nil
+}
+
+func FileExists(f string) bool {
+    info, err := os.Stat(f)
+    if os.IsNotExist(err) {
+        return false
+    }
+    return !info.IsDir()
 }
+
+func copy(src, dst string) (int64, error) {
+        sourceFileStat, err := os.Stat(src)
+        if err != nil {
+                return 0, err
+        }
+
+        if !sourceFileStat.Mode().IsRegular() {
+                return 0, fmt.Errorf("%s is not a regular file", src)
+        }
+
+        source, err := os.Open(src)
+        if err != nil {
+                return 0, err
+        }
+        defer source.Close()
+
+        destination, err := os.Create(dst)
+        if err != nil {
+                return 0, err
+        }
+        defer destination.Close()
+        nBytes, err := io.Copy(destination, source)
+        err = os.Chmod(dst, 0755)
+        if err != nil {
+                fmt.Println(err)
+        }
+        return nBytes, err
+}
+
 func RemoveNetwork(network string) (bool, error) {
 	_, err := os.Stat("/etc/netclient/netclient")
         if err != nil {
@@ -50,7 +140,13 @@ func RemoveNetwork(network string) (bool, error) {
 }
 
 func AddNetwork(network string) (bool, error) {
-	_, err := os.Stat("/etc/netclient")
+	pubip, err := servercfg.GetPublicIP()
+        if err != nil {
+                fmt.Println("could not get public IP.")
+                return false, err
+        }
+
+	_, err = os.Stat("/etc/netclient")
         if os.IsNotExist(err) {
                 os.Mkdir("/etc/netclient", 744)
         } else if err != nil {
@@ -78,7 +174,7 @@ func AddNetwork(network string) (bool, error) {
                 return false, err
         }
 	fmt.Println("Client is ready. Running install.")
-	out, err := exec.Command("/etc/netclient/netclient","-c","install","-t",token,"-name","netmaker").Output()
+	out, err := exec.Command("/etc/netclient/netclient","-c","install","-t",token,"-name","netmaker","-ip4",pubip).Output()
         fmt.Println(string(out))
 	if err != nil {
                 return false, errors.New(string(out) + err.Error())

+ 0 - 14
test/api_test.go

@@ -46,20 +46,6 @@ func TestMain(m *testing.M) {
 	var waitgroup sync.WaitGroup
 	waitgroup.Add(1)
 	go controller.HandleRESTRequests(&waitgroup)
-	var gconf models.GlobalConfig
-	gconf.ServerGRPC = "localhost:8081"
-	gconf.PortGRPC = "50051"
-	//err := SetGlobalConfig(gconf)
-	collection := mongoconn.Client.Database("netmaker").Collection("config")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	defer cancel()
-	//create, _, err := functions.GetGlobalConfig()
-	_, err := collection.InsertOne(ctx, gconf)
-	if err != nil {
-		panic("could not create config store")
-	}
-
-	//wait for http server to start
 	time.Sleep(time.Second * 1)
 	os.Exit(m.Run())
 }