瀏覽代碼

merge conflicts resolved

Abhishek Kondur 2 年之前
父節點
當前提交
92e96c2bb0
共有 15 個文件被更改,包括 187 次插入61 次删除
  1. 2 3
      README.md
  2. 2 1
      compose/docker-compose.yml
  3. 49 48
      config/config.go
  4. 48 0
      controllers/network.go
  5. 21 3
      controllers/node.go
  6. 1 1
      go.mod
  7. 3 0
      logic/gateway.go
  8. 10 0
      logic/nodes.go
  9. 24 1
      logic/relay.go
  10. 1 0
      models/host.go
  11. 4 0
      models/node.go
  12. 2 1
      mq/handlers.go
  13. 1 0
      scripts/netmaker.default.env
  14. 3 3
      scripts/nm-quick.sh
  15. 16 0
      servercfg/serverconf.go

+ 2 - 3
README.md

@@ -6,13 +6,12 @@
 </p>
 
 <p align="center">
-<a href="https://runacap.com/ross-index/q1-2022/" target="_blank" rel="noopener">
-    <img src="https://runacap.com/wp-content/uploads/2022/06/ROSS_badge_white_Q1_2022.svg" alt="ROSS Index - Fastest Growing Open-Source Startups in Q1 2022 | Runa Capital"  width="15%"/>
+<a href="https://runacap.com/ross-index/annual-2022/" target="_blank" rel="noopener">
+    <img src="https://runacap.com/wp-content/uploads/2023/02/Annual_ROSS_badge_white_2022.svg" alt="ROSS Index - Fastest Growing Open-Source Startups | Runa Capital" width="17%" />
 </a>  
 <a href="https://www.ycombinator.com/companies/netmaker/" target="_blank" rel="noopener">
     <img src="https://raw.githubusercontent.com/gravitl/netmaker-docs/master/images/netmaker-github/y-combinator.png" alt="Y-Combinator" width="16%" />
 </a>  
-
 </p>
 
 <p align="center">

+ 2 - 1
compose/docker-compose.yml

@@ -6,7 +6,7 @@ services:
     container_name: netmaker
     image: gravitl/netmaker:$SERVER_IMAGE_TAG
     env_file: ./netmaker.env
-    restart: on-failure
+    restart: always
     volumes:
       - dnsconfig:/root/config/dnsconfig
       - sqldata:/root/data
@@ -96,6 +96,7 @@ services:
     network_mode: "host"
     volumes:
       - turn_server:/etc/config
+    restart: always
 
 volumes:
   caddy_data: { } # runtime data for caddy

+ 49 - 48
config/config.go

@@ -32,54 +32,55 @@ type EnvironmentConfig struct {
 
 // ServerConfig - server conf struct
 type ServerConfig struct {
-	CoreDNSAddr          string `yaml:"corednsaddr"`
-	APIConnString        string `yaml:"apiconn"`
-	APIHost              string `yaml:"apihost"`
-	APIPort              string `yaml:"apiport"`
-	Broker               string `yam:"broker"`
-	ServerBrokerEndpoint string `yaml:"serverbrokerendpoint"`
-	BrokerType           string `yaml:"brokertype"`
-	EmqxRestEndpoint     string `yaml:"emqxrestendpoint"`
-	NetclientAutoUpdate  string `yaml:"netclientautoupdate"`
-	MasterKey            string `yaml:"masterkey"`
-	DNSKey               string `yaml:"dnskey"`
-	AllowedOrigin        string `yaml:"allowedorigin"`
-	NodeID               string `yaml:"nodeid"`
-	RestBackend          string `yaml:"restbackend"`
-	MessageQueueBackend  string `yaml:"messagequeuebackend"`
-	DNSMode              string `yaml:"dnsmode"`
-	DisableRemoteIPCheck string `yaml:"disableremoteipcheck"`
-	Version              string `yaml:"version"`
-	SQLConn              string `yaml:"sqlconn"`
-	Platform             string `yaml:"platform"`
-	Database             string `yaml:"database"`
-	Verbosity            int32  `yaml:"verbosity"`
-	AuthProvider         string `yaml:"authprovider"`
-	OIDCIssuer           string `yaml:"oidcissuer"`
-	ClientID             string `yaml:"clientid"`
-	ClientSecret         string `yaml:"clientsecret"`
-	FrontendURL          string `yaml:"frontendurl"`
-	DisplayKeys          string `yaml:"displaykeys"`
-	AzureTenant          string `yaml:"azuretenant"`
-	Telemetry            string `yaml:"telemetry"`
-	HostNetwork          string `yaml:"hostnetwork"`
-	Server               string `yaml:"server"`
-	PublicIPService      string `yaml:"publicipservice"`
-	MQPassword           string `yaml:"mqpassword"`
-	MQUserName           string `yaml:"mqusername"`
-	MetricsExporter      string `yaml:"metrics_exporter"`
-	BasicAuth            string `yaml:"basic_auth"`
-	LicenseValue         string `yaml:"license_value"`
-	NetmakerAccountID    string `yaml:"netmaker_account_id"`
-	IsEE                 string `yaml:"is_ee"`
-	StunPort             int    `yaml:"stun_port"`
-	StunList             string `yaml:"stun_list"`
-	TurnServer           string `yaml:"turn_server"`
-	TurnApiServer        string `yaml:"turn_api_server"`
-	TurnPort             int    `yaml:"turn_port"`
-	TurnUserName         string `yaml:"turn_username"`
-	TurnPassword         string `yaml:"turn_password"`
-	UseTurn              bool   `yaml:"use_turn"`
+	CoreDNSAddr                string `yaml:"corednsaddr"`
+	APIConnString              string `yaml:"apiconn"`
+	APIHost                    string `yaml:"apihost"`
+	APIPort                    string `yaml:"apiport"`
+	Broker                     string `yam:"broker"`
+	ServerBrokerEndpoint       string `yaml:"serverbrokerendpoint"`
+	BrokerType                 string `yaml:"brokertype"`
+	EmqxRestEndpoint           string `yaml:"emqxrestendpoint"`
+	NetclientAutoUpdate        string `yaml:"netclientautoupdate"`
+	NetclientEndpointDetection string `yaml:"netclientendpointdetection"`
+	MasterKey                  string `yaml:"masterkey"`
+	DNSKey                     string `yaml:"dnskey"`
+	AllowedOrigin              string `yaml:"allowedorigin"`
+	NodeID                     string `yaml:"nodeid"`
+	RestBackend                string `yaml:"restbackend"`
+	MessageQueueBackend        string `yaml:"messagequeuebackend"`
+	DNSMode                    string `yaml:"dnsmode"`
+	DisableRemoteIPCheck       string `yaml:"disableremoteipcheck"`
+	Version                    string `yaml:"version"`
+	SQLConn                    string `yaml:"sqlconn"`
+	Platform                   string `yaml:"platform"`
+	Database                   string `yaml:"database"`
+	Verbosity                  int32  `yaml:"verbosity"`
+	AuthProvider               string `yaml:"authprovider"`
+	OIDCIssuer                 string `yaml:"oidcissuer"`
+	ClientID                   string `yaml:"clientid"`
+	ClientSecret               string `yaml:"clientsecret"`
+	FrontendURL                string `yaml:"frontendurl"`
+	DisplayKeys                string `yaml:"displaykeys"`
+	AzureTenant                string `yaml:"azuretenant"`
+	Telemetry                  string `yaml:"telemetry"`
+	HostNetwork                string `yaml:"hostnetwork"`
+	Server                     string `yaml:"server"`
+	PublicIPService            string `yaml:"publicipservice"`
+	MQPassword                 string `yaml:"mqpassword"`
+	MQUserName                 string `yaml:"mqusername"`
+	MetricsExporter            string `yaml:"metrics_exporter"`
+	BasicAuth                  string `yaml:"basic_auth"`
+	LicenseValue               string `yaml:"license_value"`
+	NetmakerAccountID          string `yaml:"netmaker_account_id"`
+	IsEE                       string `yaml:"is_ee"`
+	StunPort                   int    `yaml:"stun_port"`
+	StunList                   string `yaml:"stun_list"`
+	TurnServer                 string `yaml:"turn_server"`
+	TurnApiServer              string `yaml:"turn_api_server"`
+	TurnPort                   int    `yaml:"turn_port"`
+	TurnUserName               string `yaml:"turn_username"`
+	TurnPassword               string `yaml:"turn_password"`
+	UseTurn                    bool   `yaml:"use_turn"`
 }
 
 // SQLConfig - Generic SQL Config

+ 48 - 0
controllers/network.go

@@ -8,6 +8,7 @@ import (
 	"strings"
 
 	"github.com/gorilla/mux"
+	"golang.org/x/exp/slog"
 
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/logger"
@@ -22,6 +23,7 @@ func networkHandlers(r *mux.Router) {
 	r.HandleFunc("/api/networks", logic.SecurityCheck(true, checkFreeTierLimits(networks_l, http.HandlerFunc(createNetwork)))).Methods(http.MethodPost)
 	r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(false, http.HandlerFunc(getNetwork))).Methods(http.MethodGet)
 	r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(true, http.HandlerFunc(deleteNetwork))).Methods(http.MethodDelete)
+	r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(true, http.HandlerFunc(updateNetwork))).Methods(http.MethodPut)
 	// ACLs
 	r.HandleFunc("/api/networks/{networkname}/acls", logic.SecurityCheck(true, http.HandlerFunc(updateNetworkACL))).Methods(http.MethodPut)
 	r.HandleFunc("/api/networks/{networkname}/acls", logic.SecurityCheck(true, http.HandlerFunc(getNetworkACL))).Methods(http.MethodGet)
@@ -277,3 +279,49 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(network)
 }
+
+// swagger:route PUT /api/networks networks updateNetwork
+//
+// Update pro settings for a network.
+//
+//			Schemes: https
+//
+//			Security:
+//	  		oauth
+//
+//			Responses:
+//				200: networkBodyResponse
+func updateNetwork(w http.ResponseWriter, r *http.Request) {
+
+	w.Header().Set("Content-Type", "application/json")
+
+	var payload models.Network
+
+	// we decode our body request params
+	err := json.NewDecoder(r.Body).Decode(&payload)
+	if err != nil {
+		slog.Info("error decoding request body", "user", r.Header.Get("user"), "err", err)
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+		return
+	}
+
+	netOld1, err := logic.GetNetwork(payload.NetID)
+	if err != nil {
+		slog.Info("error fetching network", "user", r.Header.Get("user"), "err", err)
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+		return
+	}
+	// partial update
+	netOld2 := netOld1
+	netOld2.ProSettings = payload.ProSettings
+	_, _, _, _, _, err = logic.UpdateNetwork(&netOld1, &netOld2)
+	if err != nil {
+		slog.Info("failed to update network", "user", r.Header.Get("user"), "err", err)
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+		return
+	}
+
+	slog.Info("updated network", "network", payload.NetID, "user", r.Header.Get("user"))
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(payload)
+}

+ 21 - 3
controllers/node.go

@@ -706,12 +706,14 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(apiNode)
 	runUpdates(newNode, ifaceDelta)
-	go func(aclUpdate bool, newNode *models.Node) {
-		mq.BroadcastAddOrUpdateNetworkPeer(&models.Client{Host: *host, Node: *newNode}, true)
+	go func(aclUpdate, relayupdate bool, newNode *models.Node) {
+		if aclUpdate || relayupdate {
+			mq.BroadcastAddOrUpdateNetworkPeer(&models.Client{Host: *host, Node: *newNode}, true)
+		}
 		if err := mq.PublishReplaceDNS(&currentNode, newNode, host); err != nil {
 			logger.Log(1, "failed to publish dns update", err.Error())
 		}
-	}(aclUpdate, newNode)
+	}(aclUpdate, relayupdate, newNode)
 }
 
 // swagger:route DELETE /api/nodes/{network}/{nodeid} nodes deleteNode
@@ -755,6 +757,22 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to delete node"), "internal"))
 		return
 	}
+	if node.IsRelayed {
+		// cleanup node from relayednodes on relay node
+		relayNode, err := logic.GetNodeByID(node.RelayedBy)
+		if err == nil {
+			relayedNodes := []string{}
+			for _, relayedNodeID := range relayNode.RelayedNodes {
+				if relayedNodeID == node.ID.String() {
+					continue
+				}
+				relayedNodes = append(relayedNodes, relayedNodeID)
+			}
+			relayNode.RelayedNodes = relayedNodes
+			logic.UpsertNode(&relayNode)
+		}
+
+	}
 	logic.ReturnSuccessResponse(w, r, nodeid+" deleted.")
 	logger.Log(1, r.Header.Get("user"), "Deleted node", nodeid, "from network", params["network"])
 	if !fromNode { // notify node change

+ 1 - 1
go.mod

@@ -10,7 +10,7 @@ require (
 	github.com/gorilla/handlers v1.5.1
 	github.com/gorilla/mux v1.8.0
 	github.com/lib/pq v1.10.9
-	github.com/mattn/go-sqlite3 v1.14.16
+	github.com/mattn/go-sqlite3 v1.14.17
 	github.com/rqlite/gorqlite v0.0.0-20210514125552-08ff1e76b22f
 	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
 	github.com/stretchr/testify v1.8.4

+ 3 - 0
logic/gateway.go

@@ -115,6 +115,9 @@ func CreateIngressGateway(netid string, nodeid string, ingress models.IngressReq
 	if host.FirewallInUse == models.FIREWALL_NONE {
 		return models.Node{}, errors.New("firewall is not supported for ingress gateways")
 	}
+	if host.NatType != models.NAT_Types.Public {
+		return models.Node{}, errors.New("ingress cannot be created on nodes behind NAT")
+	}
 
 	network, err := GetParentNetwork(netid)
 	if err != nil {

+ 10 - 0
logic/nodes.go

@@ -95,6 +95,16 @@ func UpdateNodeCheckin(node *models.Node) error {
 	return database.Insert(node.ID.String(), string(data), database.NODES_TABLE_NAME)
 }
 
+// UpsertNode - updates node in the DB
+func UpsertNode(newNode *models.Node) error {
+	newNode.SetLastModified()
+	data, err := json.Marshal(newNode)
+	if err != nil {
+		return err
+	}
+	return database.Insert(newNode.ID.String(), string(data), database.NODES_TABLE_NAME)
+}
+
 // UpdateNode - takes a node and updates another node with it's values
 func UpdateNode(currentNode *models.Node, newNode *models.Node) error {
 	if newNode.Address.IP.String() != currentNode.Address.IP.String() {

+ 24 - 1
logic/relay.go

@@ -91,13 +91,36 @@ func SetRelayedNodes(setRelayed bool, relay string, relayed []string) []models.C
 	return returnnodes
 }
 
+//func GetRelayedNodes(relayNode *models.Node) (models.Node, error) {
+//	var returnnodes []models.Node
+//	networkNodes, err := GetNetworkNodes(relayNode.Network)
+//	if err != nil {
+//		return returnnodes, err
+//	}
+//	for _, node := range networkNodes {
+//		for _, addr := range relayNode.RelayAddrs {
+//			if addr == node.Address.IP.String() || addr == node.Address6.IP.String() {
+//				returnnodes = append(returnnodes, node)
+//			}
+//		}
+//	}
+//	return returnnodes, nil
+//}
+
 // ValidateRelay - checks if relay is valid
 func ValidateRelay(relay models.RelayRequest) error {
 	var err error
 	//isIp := functions.IsIpCIDR(gateway.RangeString)
 	empty := len(relay.RelayedNodes) == 0
 	if empty {
-		err = errors.New("relayed nodes cannot be empty")
+		return errors.New("IP Ranges Cannot Be Empty")
+	}
+	node, err := GetNodeByID(relay.NodeID)
+	if err != nil {
+		return err
+	}
+	if node.IsRelay {
+		return errors.New("node is already acting as a relay")
 	}
 	for _, relayedNodeID := range relay.RelayedNodes {
 		relayedNode, err := GetNodeByID(relayedNodeID)

+ 1 - 0
models/host.go

@@ -47,6 +47,7 @@ type Host struct {
 	IPForwarding       bool             `json:"ipforwarding" yaml:"ipforwarding"`
 	DaemonInstalled    bool             `json:"daemoninstalled" yaml:"daemoninstalled"`
 	AutoUpdate         bool             `json:"autoupdate" yaml:"autoupdate"`
+	EndpointDetection  bool             `json:"endpointdetection" yaml:"endpointdetection"`
 	HostPass           string           `json:"hostpass" yaml:"hostpass"`
 	Name               string           `json:"name" yaml:"name"`
 	OS                 string           `json:"os" yaml:"os"`

+ 4 - 0
models/node.go

@@ -69,6 +69,10 @@ type CommonNode struct {
 	IsEgressGateway     bool          `json:"isegressgateway" yaml:"isegressgateway"`
 	EgressGatewayRanges []string      `json:"egressgatewayranges" bson:"egressgatewayranges" yaml:"egressgatewayranges"`
 	IsIngressGateway    bool          `json:"isingressgateway" yaml:"isingressgateway"`
+	IsRelayed           bool          `json:"isrelayed" bson:"isrelayed" yaml:"isrelayed"`
+	RelayedBy           string        `json:"relayedby" bson:"relayedby" yaml:"relayedby"`
+	IsRelay             bool          `json:"isrelay" bson:"isrelay" yaml:"isrelay"`
+	RelayedNodes        []string      `json:"relaynodes" yaml:"relayedNodes"`
 	IngressDNS          string        `json:"ingressdns" yaml:"ingressdns"`
 	IsRelayed           bool          `json:"isrelayed" yaml:"isrelayed"`
 	RelayedBy           string        `json:"relayedby" yaml:"relayedby"`

+ 2 - 1
mq/handlers.go

@@ -408,7 +408,8 @@ func handleHostCheckin(h, currentHost *models.Host) bool {
 	ifaceDelta := len(h.Interfaces) != len(currentHost.Interfaces) ||
 		!h.EndpointIP.Equal(currentHost.EndpointIP) ||
 		(len(h.NatType) > 0 && h.NatType != currentHost.NatType) ||
-		h.DefaultInterface != currentHost.DefaultInterface
+		h.DefaultInterface != currentHost.DefaultInterface ||
+		h.EndpointDetection != servercfg.EndpointDetectionEnabled()
 	if ifaceDelta { // only save if something changes
 		currentHost.EndpointIP = h.EndpointIP
 		currentHost.Interfaces = h.Interfaces

+ 1 - 0
scripts/netmaker.default.env

@@ -19,6 +19,7 @@ NETMAKER_ACCOUNT_ID=
 LICENSE_KEY=
 SERVER_IMAGE_TAG=
 UI_IMAGE_TAG=
+NETCLIENT_ENDPOINT_DETECTION="disabled"
 # used for HA - identifies this server vs other servers
 NODE_ID="netmaker-server-1"
 METRICS_EXPORTER="off"

+ 3 - 3
scripts/nm-quick.sh

@@ -303,9 +303,9 @@ save_config() { (
 	local toCopy=("SERVER_HOST" "MASTER_KEY" "TURN_USERNAME" "TURN_PASSWORD" "MQ_USERNAME" "MQ_PASSWORD"
 		"INSTALL_TYPE" "NODE_ID" "METRICS_EXPORTER" "PROMETHEUS" "DNS_MODE" "NETCLIENT_AUTO_UPDATE" "API_PORT"
 		"CORS_ALLOWED_ORIGIN" "DISPLAY_KEYS" "DATABASE" "SERVER_BROKER_ENDPOINT" "STUN_PORT" "VERBOSITY"
-		"TURN_PORT" "USE_TURN" "DEBUG_MODE" "TURN_API_PORT" "REST_BACKEND" "DISABLE_REMOTE_IP_CHECK"
-		"TELEMETRY" "AUTH_PROVIDER" "CLIENT_ID" "CLIENT_SECRET" "FRONTEND_URL" "AZURE_TENANT" "OIDC_ISSUER"
-		"EXPORTER_API_PORT")
+		"TURN_PORT" "USE_TURN" "DEBUG_MODE" "TURN_API_PORT" "REST_BACKEND"
+		"DISABLE_REMOTE_IP_CHECK" "NETCLIENT_ENDPOINT_DETECTION" "TELEMETRY" "AUTH_PROVIDER" "CLIENT_ID" "CLIENT_SECRET"
+		"FRONTEND_URL" "AZURE_TENANT" "OIDC_ISSUER" "EXPORTER_API_PORT")
 	for name in "${toCopy[@]}"; do
 		save_config_item $name "${!name}"
 	done

+ 16 - 0
servercfg/serverconf.go

@@ -51,6 +51,11 @@ func GetServerConfig() config.ServerConfig {
 	} else {
 		cfg.NetclientAutoUpdate = "disabled"
 	}
+	if EndpointDetectionEnabled() {
+		cfg.NetclientEndpointDetection = "enabled"
+	} else {
+		cfg.NetclientEndpointDetection = "disabled"
+	}
 	if IsRestBackend() {
 		cfg.RestBackend = "on"
 	}
@@ -415,6 +420,17 @@ func AutoUpdateEnabled() bool {
 	return true
 }
 
+// EndpointDetectionEnabled returns a boolean indicating whether netclient endpoint detection is enabled or disabled
+// default is enabled
+func EndpointDetectionEnabled() bool {
+	if os.Getenv("NETCLIENT_ENDPOINT_DETECTION") == "disabled" {
+		return false
+	} else if config.Config.Server.NetclientEndpointDetection == "disabled" {
+		return false
+	}
+	return true
+}
+
 // IsDNSMode - should it run with DNS
 func IsDNSMode() bool {
 	isdns := true