Ver Fonte

Merge branch 'develop' into NET-406

Matthew R Kasun há 2 anos atrás
pai
commit
36b444e13a

+ 1 - 1
Dockerfile

@@ -6,7 +6,7 @@ COPY . .
 
 RUN GOOS=linux CGO_ENABLED=1 go build -ldflags="-s -w " -tags ${tags} .
 # RUN go build -tags=ee . -o netmaker main.go
-FROM alpine:3.18.2
+FROM alpine:3.18.3
 
 # add a c lib
 # set the working directory

+ 1 - 1
Dockerfile-quick

@@ -1,5 +1,5 @@
 #first stage - builder
-FROM alpine:3.18.2
+FROM alpine:3.18.3
 ARG version 
 WORKDIR /app
 COPY ./netmaker /root/netmaker

+ 3 - 2
config/config.go

@@ -82,9 +82,10 @@ type ServerConfig struct {
 	TurnPassword               string `yaml:"turn_password"`
 	UseTurn                    bool   `yaml:"use_turn"`
 	UsersLimit                 int    `yaml:"user_limit"`
-	ClientsLimit               int    `yaml:"client_limit"`
 	NetworksLimit              int    `yaml:"network_limit"`
-	HostsLimit                 int    `yaml:"host_limit"`
+	MachinesLimit              int    `yaml:"machines_limit"`
+	IngressesLimit             int    `yaml:"ingresses_limit"`
+	EgressesLimit              int    `yaml:"egresses_limit"`
 	DeployedByOperator         bool   `yaml:"deployed_by_operator"`
 	Environment                string `yaml:"environment"`
 }

+ 7 - 2
controllers/ext_client.go

@@ -29,7 +29,7 @@ func extClientHandlers(r *mux.Router) {
 	r.HandleFunc("/api/extclients/{network}/{clientid}/{type}", logic.NetUserSecurityCheck(false, true, http.HandlerFunc(getExtClientConf))).Methods(http.MethodGet)
 	r.HandleFunc("/api/extclients/{network}/{clientid}", logic.NetUserSecurityCheck(false, true, http.HandlerFunc(updateExtClient))).Methods(http.MethodPut)
 	r.HandleFunc("/api/extclients/{network}/{clientid}", logic.NetUserSecurityCheck(false, true, http.HandlerFunc(deleteExtClient))).Methods(http.MethodDelete)
-	r.HandleFunc("/api/extclients/{network}/{nodeid}", logic.NetUserSecurityCheck(false, true, checkFreeTierLimits(clients_l, http.HandlerFunc(createExtClient)))).Methods(http.MethodPost)
+	r.HandleFunc("/api/extclients/{network}/{nodeid}", logic.NetUserSecurityCheck(false, true, checkFreeTierLimits(limitChoiceMachines, http.HandlerFunc(createExtClient)))).Methods(http.MethodPost)
 }
 
 func checkIngressExists(nodeID string) bool {
@@ -217,7 +217,12 @@ func getExtClientConf(w http.ResponseWriter, r *http.Request) {
 	if network.DefaultKeepalive != 0 {
 		keepalive = "PersistentKeepalive = " + strconv.Itoa(int(network.DefaultKeepalive))
 	}
-	gwendpoint := host.EndpointIP.String() + ":" + strconv.Itoa(host.ListenPort)
+	gwendpoint := ""
+	if host.EndpointIP.To4() == nil {
+		gwendpoint = fmt.Sprintf("[%s]:%d", host.EndpointIP.String(), host.ListenPort)
+	} else {
+		gwendpoint = fmt.Sprintf("%s:%d", host.EndpointIP.String(), host.ListenPort)
+	}
 	newAllowedIPs := network.AddressRange
 	if newAllowedIPs != "" && network.AddressRange6 != "" {
 		newAllowedIPs += ","

+ 40 - 16
controllers/limits.go

@@ -10,36 +10,60 @@ import (
 
 // limit consts
 const (
-	node_l     = 0
-	networks_l = 1
-	users_l    = 2
-	clients_l  = 3
+	limitChoiceNetworks = iota
+	limitChoiceUsers
+	limitChoiceMachines
+	limitChoiceIngress
+	limitChoiceEgress
 )
 
-func checkFreeTierLimits(limit_choice int, next http.Handler) http.HandlerFunc {
+func checkFreeTierLimits(limitChoice int, next http.Handler) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var errorResponse = models.ErrorResponse{
-			Code: http.StatusForbidden, Message: "free tier limits exceeded on networks",
+			Code: http.StatusForbidden, Message: "free tier limits exceeded on ",
 		}
 
-		if logic.Free_Tier { // check that free tier limits not exceeded
-			if limit_choice == networks_l {
+		if logic.FreeTier { // check that free tier limits not exceeded
+			switch limitChoice {
+			case limitChoiceNetworks:
 				currentNetworks, err := logic.GetNetworks()
-				if (err != nil && !database.IsEmptyRecord(err)) || len(currentNetworks) >= logic.Networks_Limit {
+				if (err != nil && !database.IsEmptyRecord(err)) ||
+					len(currentNetworks) >= logic.NetworksLimit {
+					errorResponse.Message += "networks"
 					logic.ReturnErrorResponse(w, r, errorResponse)
 					return
 				}
-			} else if limit_choice == users_l {
+			case limitChoiceUsers:
 				users, err := logic.GetUsers()
-				if (err != nil && !database.IsEmptyRecord(err)) || len(users) >= logic.Users_Limit {
-					errorResponse.Message = "free tier limits exceeded on users"
+				if (err != nil && !database.IsEmptyRecord(err)) ||
+					len(users) >= logic.UsersLimit {
+					errorResponse.Message += "users"
 					logic.ReturnErrorResponse(w, r, errorResponse)
 					return
 				}
-			} else if limit_choice == clients_l {
-				clients, err := logic.GetAllExtClients()
-				if (err != nil && !database.IsEmptyRecord(err)) || len(clients) >= logic.Clients_Limit {
-					errorResponse.Message = "free tier limits exceeded on external clients"
+			case limitChoiceMachines:
+				hosts, hErr := logic.GetAllHosts()
+				clients, cErr := logic.GetAllExtClients()
+				if (hErr != nil && !database.IsEmptyRecord(hErr)) ||
+					(cErr != nil && !database.IsEmptyRecord(cErr)) ||
+					len(hosts)+len(clients) >= logic.MachinesLimit {
+					errorResponse.Message += "machines"
+					logic.ReturnErrorResponse(w, r, errorResponse)
+					return
+				}
+			case limitChoiceIngress:
+				ingresses, err := logic.GetAllIngresses()
+				if (err != nil && !database.IsEmptyRecord(err)) ||
+					len(ingresses) >= logic.IngressesLimit {
+					errorResponse.Message += "ingresses"
+					logic.ReturnErrorResponse(w, r, errorResponse)
+					return
+				}
+			case limitChoiceEgress:
+				egresses, err := logic.GetAllEgresses()
+				if (err != nil && !database.IsEmptyRecord(err)) ||
+					len(egresses) >= logic.EgressesLimit {
+					errorResponse.Message += "egresses"
 					logic.ReturnErrorResponse(w, r, errorResponse)
 					return
 				}

+ 9 - 1
controllers/network.go

@@ -21,7 +21,7 @@ import (
 
 func networkHandlers(r *mux.Router) {
 	r.HandleFunc("/api/networks", logic.SecurityCheck(false, http.HandlerFunc(getNetworks))).Methods(http.MethodGet)
-	r.HandleFunc("/api/networks", logic.SecurityCheck(true, checkFreeTierLimits(networks_l, http.HandlerFunc(createNetwork)))).Methods(http.MethodPost)
+	r.HandleFunc("/api/networks", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceNetworks, 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)
@@ -245,6 +245,14 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
+	if len(network.NetID) > 32 {
+		err := errors.New("network name shouldn't exceed 32 characters")
+		logger.Log(0, r.Header.Get("user"), "failed to create network: ",
+			err.Error())
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+		return
+	}
+
 	if network.AddressRange == "" && network.AddressRange6 == "" {
 		err := errors.New("IPv4 or IPv6 CIDR required")
 		logger.Log(0, r.Header.Get("user"), "failed to create network: ",

+ 2 - 2
controllers/network_test.go

@@ -80,7 +80,7 @@ func TestDeleteNetwork(t *testing.T) {
 		err := logic.DeleteNetwork("skynet")
 		assert.Nil(t, err)
 	})
-	t.Run("NonExistantNetwork", func(t *testing.T) {
+	t.Run("NonExistentNetwork", func(t *testing.T) {
 		err := logic.DeleteNetwork("skynet")
 		assert.Nil(t, err)
 	})
@@ -151,7 +151,7 @@ func TestValidateNetwork(t *testing.T) {
 		{
 			testname: "NetIDTooLong",
 			network: models.Network{
-				NetID: "LongNetIDName",
+				NetID: "LongNetIDNameForMaxCharactersTest",
 			},
 			errMessage: "Field validation for 'NetID' failed on the 'max' tag",
 		},

+ 2 - 2
controllers/node.go

@@ -28,9 +28,9 @@ func nodeHandlers(r *mux.Router) {
 	r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(getNode))).Methods(http.MethodGet)
 	r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(false, true, "node", http.HandlerFunc(updateNode))).Methods(http.MethodPut)
 	r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(deleteNode))).Methods(http.MethodDelete)
-	r.HandleFunc("/api/nodes/{network}/{nodeid}/creategateway", Authorize(false, true, "user", http.HandlerFunc(createEgressGateway))).Methods(http.MethodPost)
+	r.HandleFunc("/api/nodes/{network}/{nodeid}/creategateway", Authorize(false, true, "user", checkFreeTierLimits(limitChoiceEgress, http.HandlerFunc(createEgressGateway)))).Methods(http.MethodPost)
 	r.HandleFunc("/api/nodes/{network}/{nodeid}/deletegateway", Authorize(false, true, "user", http.HandlerFunc(deleteEgressGateway))).Methods(http.MethodDelete)
-	r.HandleFunc("/api/nodes/{network}/{nodeid}/createingress", logic.SecurityCheck(false, http.HandlerFunc(createIngressGateway))).Methods(http.MethodPost)
+	r.HandleFunc("/api/nodes/{network}/{nodeid}/createingress", logic.SecurityCheck(false, checkFreeTierLimits(limitChoiceIngress, http.HandlerFunc(createIngressGateway)))).Methods(http.MethodPost)
 	r.HandleFunc("/api/nodes/{network}/{nodeid}/deleteingress", logic.SecurityCheck(false, http.HandlerFunc(deleteIngressGateway))).Methods(http.MethodDelete)
 	r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(updateNode))).Methods(http.MethodPost)
 	r.HandleFunc("/api/nodes/adm/{network}/authenticate", authenticate).Methods(http.MethodPost)

+ 16 - 4
controllers/server.go

@@ -24,12 +24,16 @@ func serverHandlers(r *mux.Router) {
 	r.HandleFunc("/api/server/status", http.HandlerFunc(getStatus)).Methods(http.MethodGet)
 	r.HandleFunc("/api/server/usage", Authorize(true, false, "user", http.HandlerFunc(getUsage))).Methods(http.MethodGet)
 }
+
+// TODO move to EE package? there is a function and a type there for that already
 func getUsage(w http.ResponseWriter, r *http.Request) {
 	type usage struct {
-		Hosts    int `json:"hosts"`
-		Clients  int `json:"clients"`
-		Networks int `json:"networks"`
-		Users    int `json:"users"`
+		Hosts     int `json:"hosts"`
+		Clients   int `json:"clients"`
+		Networks  int `json:"networks"`
+		Users     int `json:"users"`
+		Ingresses int `json:"ingresses"`
+		Egresses  int `json:"egresses"`
 	}
 	var serverUsage usage
 	hosts, err := logic.GetAllHosts()
@@ -48,6 +52,14 @@ func getUsage(w http.ResponseWriter, r *http.Request) {
 	if err == nil {
 		serverUsage.Networks = len(networks)
 	}
+	ingresses, err := logic.GetAllIngresses()
+	if err == nil {
+		serverUsage.Ingresses = len(ingresses)
+	}
+	egresses, err := logic.GetAllEgresses()
+	if err == nil {
+		serverUsage.Egresses = len(egresses)
+	}
 	w.Header().Set("Content-Type", "application/json")
 	json.NewEncoder(w).Encode(models.SuccessResponse{
 		Code:     http.StatusOK,

+ 1 - 1
controllers/user.go

@@ -30,7 +30,7 @@ func userHandlers(r *mux.Router) {
 	r.HandleFunc("/api/users/{username}", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(updateUser)))).Methods(http.MethodPut)
 	r.HandleFunc("/api/users/networks/{username}", logic.SecurityCheck(true, http.HandlerFunc(updateUserNetworks))).Methods(http.MethodPut)
 	r.HandleFunc("/api/users/{username}/adm", logic.SecurityCheck(true, http.HandlerFunc(updateUserAdm))).Methods(http.MethodPut)
-	r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, checkFreeTierLimits(users_l, http.HandlerFunc(createUser)))).Methods(http.MethodPost)
+	r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceUsers, http.HandlerFunc(createUser)))).Methods(http.MethodPost)
 	r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, http.HandlerFunc(deleteUser))).Methods(http.MethodDelete)
 	r.HandleFunc("/api/users/{username}", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUser)))).Methods(http.MethodGet)
 	r.HandleFunc("/api/users", logic.SecurityCheck(true, http.HandlerFunc(getUsers))).Methods(http.MethodGet)

+ 1 - 1
ee/license.go

@@ -81,7 +81,7 @@ func ValidateLicense() (err error) {
 
 	licenseSecret := LicenseSecret{
 		AssociatedID: netmakerTenantID,
-		Limits:       getCurrentServerLimit(),
+		Usage:        getCurrentServerUsage(),
 	}
 
 	secretData, err := json.Marshal(&licenseSecret)

+ 26 - 20
ee/types.go

@@ -24,15 +24,17 @@ var errValidation = fmt.Errorf(license_validation_err_msg)
 
 // LicenseKey - the license key struct representation with associated data
 type LicenseKey struct {
-	LicenseValue  string `json:"license_value"` // actual (public) key and the unique value for the key
-	Expiration    int64  `json:"expiration"`
-	LimitServers  int    `json:"limit_servers"`
-	LimitUsers    int    `json:"limit_users"`
-	LimitHosts    int    `json:"limit_hosts"`
-	LimitNetworks int    `json:"limit_networks"`
-	LimitClients  int    `json:"limit_clients"`
-	Metadata      string `json:"metadata"`
-	IsActive      bool   `json:"is_active"` // yes if active
+	LicenseValue   string `json:"license_value"` // actual (public) key and the unique value for the key
+	Expiration     int64  `json:"expiration"`
+	UsageServers   int    `json:"usage_servers"`
+	UsageUsers     int    `json:"usage_users"`
+	UsageClients   int    `json:"usage_clients"`
+	UsageHosts     int    `json:"usage_hosts"`
+	UsageNetworks  int    `json:"usage_networks"`
+	UsageIngresses int    `json:"usage_ingresses"`
+	UsageEgresses  int    `json:"usage_egresses"`
+	Metadata       string `json:"metadata"`
+	IsActive       bool   `json:"is_active"` // yes if active
 }
 
 // ValidatedLicense - the validated license struct
@@ -43,26 +45,30 @@ type ValidatedLicense struct {
 
 // LicenseSecret - the encrypted struct for sending user-id
 type LicenseSecret struct {
-	AssociatedID string        `json:"associated_id" binding:"required"` // UUID for user foreign key to User table
-	Limits       LicenseLimits `json:"limits" binding:"required"`
+	AssociatedID string `json:"associated_id" binding:"required"` // UUID for user foreign key to User table
+	Usage        Usage  `json:"usage" binding:"required"`
 }
 
-// LicenseLimits - struct license limits
-type LicenseLimits struct {
-	Servers  int `json:"servers"`
-	Users    int `json:"users"`
-	Hosts    int `json:"hosts"`
-	Clients  int `json:"clients"`
-	Networks int `json:"networks"`
+// Usage - struct for license usage
+type Usage struct {
+	Servers   int `json:"servers"`
+	Users     int `json:"users"`
+	Hosts     int `json:"hosts"`
+	Clients   int `json:"clients"`
+	Networks  int `json:"networks"`
+	Ingresses int `json:"ingresses"`
+	Egresses  int `json:"egresses"`
 }
 
-// LicenseLimits.SetDefaults - sets the default values for limits
-func (l *LicenseLimits) SetDefaults() {
+// Usage.SetDefaults - sets the default values for usage
+func (l *Usage) SetDefaults() {
 	l.Clients = 0
 	l.Servers = 1
 	l.Hosts = 0
 	l.Users = 1
 	l.Networks = 0
+	l.Ingresses = 0
+	l.Egresses = 0
 }
 
 // ValidateLicenseRequest - used for request to validate license endpoint

+ 14 - 5
ee/util.go

@@ -30,14 +30,15 @@ func base64decode(input string) []byte {
 
 	return bytes
 }
-func getCurrentServerLimit() (limits LicenseLimits) {
+
+func getCurrentServerUsage() (limits Usage) {
 	limits.SetDefaults()
-	hosts, err := logic.GetAllHosts()
-	if err == nil {
+	hosts, hErr := logic.GetAllHosts()
+	if hErr == nil {
 		limits.Hosts = len(hosts)
 	}
-	clients, err := logic.GetAllExtClients()
-	if err == nil {
+	clients, cErr := logic.GetAllExtClients()
+	if cErr == nil {
 		limits.Clients = len(clients)
 	}
 	users, err := logic.GetUsers()
@@ -48,5 +49,13 @@ func getCurrentServerLimit() (limits LicenseLimits) {
 	if err == nil {
 		limits.Networks = len(networks)
 	}
+	ingresses, err := logic.GetAllIngresses()
+	if err == nil {
+		limits.Ingresses = len(ingresses)
+	}
+	egresses, err := logic.GetAllEgresses()
+	if err == nil {
+		limits.Egresses = len(egresses)
+	}
 	return
 }

+ 6 - 6
go.mod

@@ -4,7 +4,7 @@ go 1.19
 
 require (
 	github.com/eclipse/paho.mqtt.golang v1.4.3
-	github.com/go-playground/validator/v10 v10.14.1
+	github.com/go-playground/validator/v10 v10.15.0
 	github.com/golang-jwt/jwt/v4 v4.5.0
 	github.com/google/uuid v1.3.0
 	github.com/gorilla/handlers v1.5.1
@@ -15,11 +15,11 @@ require (
 	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
 	github.com/stretchr/testify v1.8.4
 	github.com/txn2/txeh v1.4.0
-	golang.org/x/crypto v0.11.0
-	golang.org/x/net v0.12.0 // indirect
-	golang.org/x/oauth2 v0.10.0
-	golang.org/x/sys v0.10.0 // indirect
-	golang.org/x/text v0.11.0 // indirect
+	golang.org/x/crypto v0.12.0
+	golang.org/x/net v0.14.0 // indirect
+	golang.org/x/oauth2 v0.11.0
+	golang.org/x/sys v0.11.0 // indirect
+	golang.org/x/text v0.12.0 // indirect
 	golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220324164955-056925b7df31
 	google.golang.org/protobuf v1.31.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1

+ 12 - 12
go.sum

@@ -30,8 +30,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
 github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
 github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
 github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
-github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k=
-github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
+github.com/go-playground/validator/v10 v10.15.0 h1:nDU5XeOKtB3GEa+uB7GNYwhVKsgjAR7VgKoNB6ryXfw=
+github.com/go-playground/validator/v10 v10.15.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
 github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
 github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -112,8 +112,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
 golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
-golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
+golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
+golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
 golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
 golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -123,10 +123,10 @@ golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qx
 golang.org/x/net v0.0.0-20211111083644-e5c967477495/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
-golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
-golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8=
-golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI=
+golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
+golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
+golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU=
+golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
 golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -141,8 +141,8 @@ golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220207234003-57398862261d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
-golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
+golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -150,8 +150,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
-golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
+golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

+ 36 - 12
logic/gateway.go

@@ -11,6 +11,36 @@ import (
 	"github.com/gravitl/netmaker/servercfg"
 )
 
+// GetAllIngresses - gets all the hosts that are ingresses
+func GetAllIngresses() ([]models.Node, error) {
+	nodes, err := GetAllNodes()
+	if err != nil {
+		return nil, err
+	}
+	ingresses := make([]models.Node, 0)
+	for _, node := range nodes {
+		if node.IsIngressGateway {
+			ingresses = append(ingresses, node)
+		}
+	}
+	return ingresses, nil
+}
+
+// GetAllEgresses - gets all the hosts that are egresses
+func GetAllEgresses() ([]models.Node, error) {
+	nodes, err := GetAllNodes()
+	if err != nil {
+		return nil, err
+	}
+	egresses := make([]models.Node, 0)
+	for _, node := range nodes {
+		if node.IsEgressGateway {
+			egresses = append(egresses, node)
+		}
+	}
+	return egresses, nil
+}
+
 // CreateEgressGateway - creates an egress gateway
 func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, error) {
 	node, err := GetNodeByID(gateway.NodeID)
@@ -28,10 +58,13 @@ func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, erro
 		return models.Node{}, errors.New("firewall is not supported for egress gateways")
 	}
 	for i := len(gateway.Ranges) - 1; i >= 0; i-- {
+		// check if internet gateway IPv4
+		if gateway.Ranges[i] == "0.0.0.0/0" && FreeTier {
+			return models.Node{}, fmt.Errorf("currently IPv4 internet gateways are not supported on the free tier: %s", gateway.Ranges[i])
+		}
+		// check if internet gateway IPv6
 		if gateway.Ranges[i] == "::/0" {
-			logger.Log(0, "currently IPv6 internet gateways are not supported", gateway.Ranges[i])
-			gateway.Ranges = append(gateway.Ranges[:i], gateway.Ranges[i+1:]...)
-			continue
+			return models.Node{}, fmt.Errorf("currently IPv6 internet gateways are not supported: %s", gateway.Ranges[i])
 		}
 		normalized, err := NormalizeCIDR(gateway.Ranges[i])
 		if err != nil {
@@ -150,15 +183,6 @@ func DeleteIngressGateway(nodeid string) (models.Node, bool, []models.ExtClient,
 	node.IsIngressGateway = false
 	node.IngressGatewayRange = ""
 	node.Failover = false
-
-	//logger.Log(3, "deleting ingress gateway firewall in use is '", host.FirewallInUse, "' and isEgressGateway is", node.IsEgressGateway)
-	if node.EgressGatewayRequest.NodeID != "" {
-		_, err := CreateEgressGateway(node.EgressGatewayRequest)
-		if err != nil {
-			logger.Log(0, fmt.Sprintf("failed to create egress gateway on node [%s] on network [%s]: %v",
-				node.EgressGatewayRequest.NodeID, node.EgressGatewayRequest.NetID, err))
-		}
-	}
 	err = UpsertNode(&node)
 	if err != nil {
 		return models.Node{}, wasFailover, removedClients, err

+ 7 - 7
logic/hosts.go

@@ -158,14 +158,14 @@ func GetHost(hostid string) (*models.Host, error) {
 
 // CreateHost - creates a host if not exist
 func CreateHost(h *models.Host) error {
-	hosts, err := GetAllHosts()
-	if err != nil && !database.IsEmptyRecord(err) {
-		return err
+	hosts, hErr := GetAllHosts()
+	clients, cErr := GetAllExtClients()
+	if (hErr != nil && !database.IsEmptyRecord(hErr)) ||
+		(cErr != nil && !database.IsEmptyRecord(cErr)) ||
+		len(hosts)+len(clients) >= MachinesLimit {
+		return errors.New("free tier limits exceeded on machines")
 	}
-	if len(hosts) >= Hosts_Limit {
-		return errors.New("free tier limits exceeded on hosts")
-	}
-	_, err = GetHost(h.ID.String())
+	_, err := GetHost(h.ID.String())
 	if (err != nil && !database.IsEmptyRecord(err)) || (err == nil) {
 		return ErrHostExists
 	}

+ 19 - 16
logic/serverconf.go

@@ -2,22 +2,23 @@ package logic
 
 import (
 	"encoding/json"
-
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/servercfg"
 )
 
 var (
-	// Networks_Limit - dummy var for community
-	Networks_Limit = 1000000000
-	// Users_Limit - dummy var for community
-	Users_Limit = 1000000000
-	// Clients_Limit - dummy var for community
-	Clients_Limit = 1000000000
-	// Hosts_Limit - dummy var for community
-	Hosts_Limit = 1000000000
-	// Free_Tier - specifies if free tier
-	Free_Tier = false
+	// NetworksLimit - dummy var for community
+	NetworksLimit = 1000000000
+	// UsersLimit - dummy var for community
+	UsersLimit = 1000000000
+	// MachinesLimit - dummy var for community
+	MachinesLimit = 1000000000
+	// IngressesLimit - dummy var for community
+	IngressesLimit = 1000000000
+	// EgressesLimit - dummy var for community
+	EgressesLimit = 1000000000
+	// FreeTier - specifies if free tier
+	FreeTier = false
 )
 
 type serverData struct {
@@ -87,10 +88,12 @@ func StoreJWTSecret(privateKey string) error {
 	return database.Insert("nm-jwt-secret", string(data), database.SERVERCONF_TABLE_NAME)
 }
 
+// SetFreeTierLimits - sets limits for free tier
 func SetFreeTierLimits() {
-	Free_Tier = true
-	Users_Limit = servercfg.GetUserLimit()
-	Clients_Limit = servercfg.GetClientLimit()
-	Networks_Limit = servercfg.GetNetworkLimit()
-	Hosts_Limit = servercfg.GetHostLimit()
+	FreeTier = true
+	UsersLimit = servercfg.GetUserLimit()
+	NetworksLimit = servercfg.GetNetworkLimit()
+	MachinesLimit = servercfg.GetMachinesLimit()
+	IngressesLimit = servercfg.GetIngressLimit()
+	EgressesLimit = servercfg.GetEgressLimit()
 }

+ 4 - 4
models/network.go

@@ -11,10 +11,10 @@ import (
 type Network struct {
 	AddressRange        string                `json:"addressrange" bson:"addressrange" validate:"omitempty,cidrv4"`
 	AddressRange6       string                `json:"addressrange6" bson:"addressrange6" validate:"omitempty,cidrv6"`
-	NetID               string                `json:"netid" bson:"netid" validate:"required,min=1,max=12,netid_valid"`
+	NetID               string                `json:"netid" bson:"netid" validate:"required,min=1,max=32,netid_valid"`
 	NodesLastModified   int64                 `json:"nodeslastmodified" bson:"nodeslastmodified"`
 	NetworkLastModified int64                 `json:"networklastmodified" bson:"networklastmodified"`
-	DefaultInterface    string                `json:"defaultinterface" bson:"defaultinterface" validate:"min=1,max=15"`
+	DefaultInterface    string                `json:"defaultinterface" bson:"defaultinterface" validate:"min=1,max=35"`
 	DefaultListenPort   int32                 `json:"defaultlistenport,omitempty" bson:"defaultlistenport,omitempty" validate:"omitempty,min=1024,max=65535"`
 	NodeLimit           int32                 `json:"nodelimit" bson:"nodelimit"`
 	DefaultPostDown     string                `json:"defaultpostdown" bson:"defaultpostdown"`
@@ -30,7 +30,7 @@ type Network struct {
 
 // SaveData - sensitive fields of a network that should be kept the same
 type SaveData struct { // put sensitive fields here
-	NetID string `json:"netid" bson:"netid" validate:"required,min=1,max=12,netid_valid"`
+	NetID string `json:"netid" bson:"netid" validate:"required,min=1,max=32,netid_valid"`
 }
 
 // Network.SetNodesLastModified - sets nodes last modified on network, depricated
@@ -49,7 +49,7 @@ func (network *Network) SetDefaults() {
 		network.DefaultUDPHolePunch = "no"
 	}
 	if network.DefaultInterface == "" {
-		if len(network.NetID) < 13 {
+		if len(network.NetID) < 33 {
 			network.DefaultInterface = "nm-" + network.NetID
 		} else {
 			network.DefaultInterface = network.NetID

+ 18 - 16
servercfg/serverconf.go

@@ -753,26 +753,28 @@ func GetNetworkLimit() int {
 	return networkslimit
 }
 
-// GetClientLimit - fetches free tier limits on ext. clients
-func GetClientLimit() int {
-	var clientsLimit int
-	if os.Getenv("CLIENTS_LIMIT") != "" {
-		clientsLimit, _ = strconv.Atoi(os.Getenv("CLIENTS_LIMIT"))
-	} else {
-		clientsLimit = config.Config.Server.ClientsLimit
+// GetMachinesLimit - fetches free tier limits on machines (clients + hosts)
+func GetMachinesLimit() int {
+	if l, err := strconv.Atoi(os.Getenv("MACHINES_LIMIT")); err == nil {
+		return l
 	}
-	return clientsLimit
+	return config.Config.Server.MachinesLimit
 }
 
-// GetHostLimit - fetches free tier limits on hosts
-func GetHostLimit() int {
-	var hostsLimit int
-	if os.Getenv("HOSTS_LIMIT") != "" {
-		hostsLimit, _ = strconv.Atoi(os.Getenv("HOSTS_LIMIT"))
-	} else {
-		hostsLimit = config.Config.Server.HostsLimit
+// GetIngressLimit - fetches free tier limits on ingresses
+func GetIngressLimit() int {
+	if l, err := strconv.Atoi(os.Getenv("INGRESSES_LIMIT")); err == nil {
+		return l
+	}
+	return config.Config.Server.IngressesLimit
+}
+
+// GetEgressLimit - fetches free tier limits on egresses
+func GetEgressLimit() int {
+	if l, err := strconv.Atoi(os.Getenv("EGRESSES_LIMIT")); err == nil {
+		return l
 	}
-	return hostsLimit
+	return config.Config.Server.EgressesLimit
 }
 
 // DeployedByOperator - returns true if the instance is deployed by netmaker operator