Browse Source

merge conflicts resolved

Abhishek Kondur 2 years ago
parent
commit
bd878f79c1
83 changed files with 1616 additions and 3603 deletions
  1. 22 0
      cli/cmd/host/create_relay.go
  2. 20 0
      cli/cmd/host/delete_relay.go
  3. 1 0
      cli/cmd/host/update.go
  4. 0 10
      cli/cmd/network/create.go
  5. 0 4
      cli/cmd/network/flags.go
  6. 0 10
      cli/cmd/network/update.go
  7. 0 22
      cli/cmd/node/create_relay.go
  8. 0 20
      cli/cmd/node/delete_relay.go
  9. 1 2
      cli/cmd/node/update.go
  10. 14 0
      cli/functions/host.go
  11. 0 14
      cli/functions/node.go
  12. 0 12
      compose/docker-compose.ee.yml
  13. 0 14
      compose/docker-compose.reference.yml
  14. 0 11
      compose/docker-compose.yml
  15. 0 3
      config/config.go
  16. 1 17
      controllers/dns.go
  17. 67 49
      controllers/dns_test.go
  18. 126 5
      controllers/hosts.go
  19. 78 0
      controllers/migrate.go
  20. 2 18
      controllers/network.go
  21. 20 11
      controllers/network_test.go
  22. 66 104
      controllers/node.go
  23. 101 73
      controllers/node_test.go
  24. 0 1
      dev.yaml
  25. 1 0
      ee/logic/failover.go
  26. 2 4
      go.mod
  27. 2 7
      go.sum
  28. 0 5
      logic/accesskeys.go
  29. 33 6
      logic/dns.go
  30. 0 11
      logic/extpeers.go
  31. 3 246
      logic/gateway.go
  32. 62 0
      logic/host_test.go
  33. 85 4
      logic/hosts.go
  34. 1 1
      logic/jwts.go
  35. 1 1
      logic/metrics/metrics.go
  36. 7 62
      logic/networks.go
  37. 6 70
      logic/nodes.go
  38. 99 76
      logic/peers.go
  39. 10 4
      logic/pro/networkuser_test.go
  40. 0 8
      logic/server.go
  41. 0 3
      logic/serverconf.go
  42. 4 58
      logic/util.go
  43. 8 6
      logic/zombie.go
  44. 9 7
      main.go
  45. 111 0
      metrics/metrics.go
  46. 2 3
      models/accessToken.go
  47. 2 13
      models/api_host.go
  48. 3 8
      models/api_node.go
  49. 1 1
      models/dnsEntry.go
  50. 0 2
      models/extclient.go
  51. 0 2
      models/host.go
  52. 8 0
      models/migrate.go
  53. 39 15
      models/mqtt.go
  54. 1 7
      models/network.go
  55. 0 9
      models/network_test.go
  56. 3 31
      models/node.go
  57. 68 0
      models/proxy.go
  58. 0 2
      models/structs.go
  59. 13 38
      mq/handlers.go
  60. 3 9
      mq/publishers.go
  61. 0 2
      netclient/ncutils/iface.go
  62. BIN
      nm-proxy/bin/proxy.linux
  63. 0 45
      nm-proxy/common/common.go
  64. 0 22
      nm-proxy/common/functions.go
  65. 0 424
      nm-proxy/manager/manager.go
  66. 0 56
      nm-proxy/metrics/metrics.go
  67. 0 65
      nm-proxy/models/models.go
  68. 0 47
      nm-proxy/nm-proxy.go
  69. 0 174
      nm-proxy/packet/packet.go
  70. 0 52
      nm-proxy/packet/packet_helper.go
  71. 0 113
      nm-proxy/packet/utils.go
  72. 0 83
      nm-proxy/peer/peer.go
  73. 0 266
      nm-proxy/proxy/proxy.go
  74. 0 245
      nm-proxy/proxy/proxy_helper.go
  75. 0 285
      nm-proxy/server/server.go
  76. 0 69
      nm-proxy/stun/stun.go
  77. 0 321
      nm-proxy/wg/wg.go
  78. 509 0
      scripts/nm-upgrade.sh
  79. 0 49
      servercfg/serverconf.go
  80. 0 136
      serverctl/iptables.go
  81. 1 1
      serverctl/serverctl.go
  82. 0 26
      swagger.yaml
  83. 0 3
      test/network_test.go.bak

+ 22 - 0
cli/cmd/host/create_relay.go

@@ -0,0 +1,22 @@
+package host
+
+import (
+	"strings"
+
+	"github.com/gravitl/netmaker/cli/functions"
+	"github.com/spf13/cobra"
+)
+
+var hostCreateRelayCmd = &cobra.Command{
+	Use:   "create_relay [HOST ID] [RELAYED HOST IDS (comma separated)]",
+	Args:  cobra.ExactArgs(2),
+	Short: "Turn a Host into a Relay",
+	Long:  `Turn a Host into a Relay`,
+	Run: func(cmd *cobra.Command, args []string) {
+		functions.PrettyPrint(functions.CreateRelay(args[0], strings.Split(args[1], ",")))
+	},
+}
+
+func init() {
+	rootCmd.AddCommand(hostCreateRelayCmd)
+}

+ 20 - 0
cli/cmd/host/delete_relay.go

@@ -0,0 +1,20 @@
+package host
+
+import (
+	"github.com/gravitl/netmaker/cli/functions"
+	"github.com/spf13/cobra"
+)
+
+var hostDeleteRelayCmd = &cobra.Command{
+	Use:   "delete_relay [HOST ID]",
+	Args:  cobra.ExactArgs(1),
+	Short: "Delete Relay role from a host",
+	Long:  `Delete Relay role from a host`,
+	Run: func(cmd *cobra.Command, args []string) {
+		functions.PrettyPrint(functions.DeleteRelay(args[0]))
+	},
+}
+
+func init() {
+	rootCmd.AddCommand(hostDeleteRelayCmd)
+}

+ 1 - 0
cli/cmd/host/update.go

@@ -38,6 +38,7 @@ var hostUpdateCmd = &cobra.Command{
 				log.Fatal(err)
 			}
 		} else {
+			apiHost.ID = args[0]
 			apiHost.EndpointIP = endpoint
 			apiHost.Name = name
 			apiHost.ListenPort = listenPort

+ 0 - 10
cli/cmd/network/create.go

@@ -41,19 +41,13 @@ var networkCreateCmd = &cobra.Command{
 			if defaultACL {
 				network.DefaultACL = "yes"
 			}
-			if pointToSite {
-				network.IsPointToSite = "yes"
-			}
 			network.DefaultInterface = defaultInterface
 			network.DefaultListenPort = int32(defaultListenPort)
 			network.NodeLimit = int32(nodeLimit)
-			network.DefaultPostUp = defaultPostUp
-			network.DefaultPostDown = defaultPostDown
 			network.DefaultKeepalive = int32(defaultKeepalive)
 			if allowManualSignUp {
 				network.AllowManualSignUp = "yes"
 			}
-			network.LocalRange = localRange
 			network.DefaultExtClientDNS = defaultExtClientDNS
 			network.DefaultMTU = int32(defaultMTU)
 		}
@@ -70,11 +64,7 @@ func init() {
 	networkCreateCmd.Flags().BoolVar(&udpHolePunch, "udp_hole_punch", false, "Enable UDP Hole Punching ?")
 	networkCreateCmd.Flags().BoolVar(&localNetwork, "local", false, "Is the network local (LAN) ?")
 	networkCreateCmd.Flags().BoolVar(&defaultACL, "default_acl", false, "Enable default Access Control List ?")
-	networkCreateCmd.Flags().BoolVar(&pointToSite, "point_to_site", false, "Enforce all clients to have only 1 central peer ?")
 	networkCreateCmd.Flags().StringVar(&defaultInterface, "interface", "", "Name of the network interface")
-	networkCreateCmd.Flags().StringVar(&defaultPostUp, "post_up", "", "Commands to run after server is up `;` separated")
-	networkCreateCmd.Flags().StringVar(&defaultPostDown, "post_down", "", "Commands to run after server is down `;` separated")
-	networkCreateCmd.Flags().StringVar(&localRange, "local_range", "", "Local CIDR range")
 	networkCreateCmd.Flags().StringVar(&defaultExtClientDNS, "ext_client_dns", "", "IPv4 address of DNS server to be used by external clients")
 	networkCreateCmd.Flags().IntVar(&defaultListenPort, "listen_port", 51821, "Default wireguard port each node will attempt to use")
 	networkCreateCmd.Flags().IntVar(&nodeLimit, "node_limit", 999999999, "Maximum number of nodes that can be associated with this network")

+ 0 - 4
cli/cmd/network/flags.go

@@ -8,15 +8,11 @@ var (
 	udpHolePunch              bool
 	localNetwork              bool
 	defaultACL                bool
-	pointToSite               bool
 	defaultInterface          string
 	defaultListenPort         int
 	nodeLimit                 int
-	defaultPostUp             string
-	defaultPostDown           string
 	defaultKeepalive          int
 	allowManualSignUp         bool
-	localRange                string
 	defaultExtClientDNS       string
 	defaultMTU                int
 )

+ 0 - 10
cli/cmd/network/update.go

@@ -44,19 +44,13 @@ var networkUpdateCmd = &cobra.Command{
 			if defaultACL {
 				network.DefaultACL = "yes"
 			}
-			if pointToSite {
-				network.IsPointToSite = "yes"
-			}
 			network.DefaultInterface = defaultInterface
 			network.DefaultListenPort = int32(defaultListenPort)
 			network.NodeLimit = int32(nodeLimit)
-			network.DefaultPostUp = defaultPostUp
-			network.DefaultPostDown = defaultPostDown
 			network.DefaultKeepalive = int32(defaultKeepalive)
 			if allowManualSignUp {
 				network.AllowManualSignUp = "yes"
 			}
-			network.LocalRange = localRange
 			network.DefaultExtClientDNS = defaultExtClientDNS
 			network.DefaultMTU = int32(defaultMTU)
 		}
@@ -71,11 +65,7 @@ func init() {
 	networkUpdateCmd.Flags().BoolVar(&udpHolePunch, "udp_hole_punch", false, "Enable UDP Hole Punching ?")
 	networkUpdateCmd.Flags().BoolVar(&localNetwork, "local", false, "Is the network local (LAN) ?")
 	networkUpdateCmd.Flags().BoolVar(&defaultACL, "default_acl", false, "Enable default Access Control List ?")
-	networkUpdateCmd.Flags().BoolVar(&pointToSite, "point_to_site", false, "Enforce all clients to have only 1 central peer ?")
 	networkUpdateCmd.Flags().StringVar(&defaultInterface, "interface", "", "Name of the network interface")
-	networkUpdateCmd.Flags().StringVar(&defaultPostUp, "post_up", "", "Commands to run after server is up `;` separated")
-	networkUpdateCmd.Flags().StringVar(&defaultPostDown, "post_down", "", "Commands to run after server is down `;` separated")
-	networkUpdateCmd.Flags().StringVar(&localRange, "local_range", "", "Local CIDR range")
 	networkUpdateCmd.Flags().StringVar(&defaultExtClientDNS, "ext_client_dns", "", "IPv4 address of DNS server to be used by external clients")
 	networkUpdateCmd.Flags().IntVar(&defaultListenPort, "listen_port", 0, "Default wireguard port each node will attempt to use")
 	networkUpdateCmd.Flags().IntVar(&nodeLimit, "node_limit", 0, "Maximum number of nodes that can be associated with this network")

+ 0 - 22
cli/cmd/node/create_relay.go

@@ -1,22 +0,0 @@
-package node
-
-import (
-	"strings"
-
-	"github.com/gravitl/netmaker/cli/functions"
-	"github.com/spf13/cobra"
-)
-
-var nodeCreateRelayCmd = &cobra.Command{
-	Use:   "create_relay [NETWORK NAME] [NODE ID] [RELAY ADDRESSES (comma separated)]",
-	Args:  cobra.ExactArgs(3),
-	Short: "Turn a Node into a Relay",
-	Long:  `Turn a Node into a Relay`,
-	Run: func(cmd *cobra.Command, args []string) {
-		functions.PrettyPrint(functions.CreateRelay(args[0], args[1], strings.Split(args[2], ",")))
-	},
-}
-
-func init() {
-	rootCmd.AddCommand(nodeCreateRelayCmd)
-}

+ 0 - 20
cli/cmd/node/delete_relay.go

@@ -1,20 +0,0 @@
-package node
-
-import (
-	"github.com/gravitl/netmaker/cli/functions"
-	"github.com/spf13/cobra"
-)
-
-var nodeDeleteRelayCmd = &cobra.Command{
-	Use:   "delete_relay [NETWORK NAME] [NODE ID]",
-	Args:  cobra.ExactArgs(2),
-	Short: "Delete Relay role from a Node",
-	Long:  `Delete Relay role from a Node`,
-	Run: func(cmd *cobra.Command, args []string) {
-		functions.PrettyPrint(functions.DeleteRelay(args[0], args[1]))
-	},
-}
-
-func init() {
-	rootCmd.AddCommand(nodeDeleteRelayCmd)
-}

+ 1 - 2
cli/cmd/node/update.go

@@ -34,8 +34,6 @@ var nodeUpdateCmd = &cobra.Command{
 			node.Address = address
 			node.Address6 = address6
 			node.LocalAddress = localAddress
-			node.PostUp = postUp
-			node.PostDown = postDown
 			node.PersistentKeepalive = int32(keepAlive)
 			if relayAddrs != "" {
 				node.RelayAddrs = strings.Split(relayAddrs, ",")
@@ -50,6 +48,7 @@ var nodeUpdateCmd = &cobra.Command{
 			node.DNSOn = dnsOn
 			node.Connected = !disconnect
 		}
+		node.HostID = functions.GetNodeByID(networkName, nodeID).Host.ID.String()
 		functions.PrettyPrint(functions.UpdateNode(networkName, nodeID, node))
 	},
 }

+ 14 - 0
cli/functions/host.go

@@ -1,6 +1,7 @@
 package functions
 
 import (
+	"fmt"
 	"net/http"
 
 	"github.com/gravitl/netmaker/models"
@@ -31,3 +32,16 @@ func UpdateHostNetworks(hostID string, networks []string) *hostNetworksUpdatePay
 		Networks: networks,
 	})
 }
+
+// CreateRelay - turn a host into a relay
+func CreateRelay(hostID string, relayedHosts []string) *models.ApiHost {
+	return request[models.ApiHost](http.MethodPost, fmt.Sprintf("/api/hosts/%s/relay", hostID), &models.HostRelayRequest{
+		HostID:       hostID,
+		RelayedHosts: relayedHosts,
+	})
+}
+
+// DeleteRelay - remove relay role from a host
+func DeleteRelay(hostID string) *models.ApiHost {
+	return request[models.ApiHost](http.MethodDelete, fmt.Sprintf("/api/hosts/%s/relay", hostID), nil)
+}

+ 0 - 14
cli/functions/node.go

@@ -31,20 +31,6 @@ func DeleteNode(networkName, nodeID string) *models.SuccessResponse {
 	return request[models.SuccessResponse](http.MethodDelete, fmt.Sprintf("/api/nodes/%s/%s", networkName, nodeID), nil)
 }
 
-// CreateRelay - turn a node into a relay
-func CreateRelay(networkName, nodeID string, relayAddresses []string) *models.ApiNode {
-	return request[models.ApiNode](http.MethodPost, fmt.Sprintf("/api/nodes/%s/%s/createrelay", networkName, nodeID), &models.RelayRequest{
-		NetID:      networkName,
-		NodeID:     nodeID,
-		RelayAddrs: relayAddresses,
-	})
-}
-
-// DeleteRelay - remove relay role from a node
-func DeleteRelay(networkName, nodeID string) *models.ApiNode {
-	return request[models.ApiNode](http.MethodDelete, fmt.Sprintf("/api/nodes/%s/%s/deleterelay", networkName, nodeID), nil)
-}
-
 // CreateEgress - turn a node into an egress
 func CreateEgress(networkName, nodeID string, payload *models.EgressGatewayRequest) *models.ApiNode {
 	return request[models.ApiNode](http.MethodPost, fmt.Sprintf("/api/nodes/%s/%s/creategateway", networkName, nodeID), payload)

+ 0 - 12
compose/docker-compose.ee.yml

@@ -4,15 +4,6 @@ services:
   netmaker:
     container_name: netmaker
     image: gravitl/netmaker:v0.17.1-ee
-    cap_add: 
-      - NET_ADMIN
-      - NET_RAW
-      - SYS_MODULE
-    sysctls:
-      - net.ipv4.ip_forward=1
-      - net.ipv4.conf.all.src_valid_mark=1
-      - net.ipv6.conf.all.disable_ipv6=0
-      - net.ipv6.conf.all.forwarding=1
     restart: always
     volumes:
       - dnsconfig:/root/config/dnsconfig
@@ -35,10 +26,7 @@ services:
       MQ_HOST: "mq"
       MQ_PORT: "443"
       MQ_SERVER_PORT: "1883"
-      HOST_NETWORK: "off"
       VERBOSITY: "1"
-      MANAGE_IPTABLES: "on"
-      PORT_FORWARD_SERVICES: "dns"
       METRICS_EXPORTER: "on"
       LICENSE_KEY: "YOUR_LICENSE_KEY"
       NETMAKER_ACCOUNT_ID: "YOUR_ACCOUNT_ID"

+ 0 - 14
compose/docker-compose.reference.yml

@@ -4,15 +4,6 @@ services:
   netmaker: # The Primary Server for running Netmaker
     container_name: netmaker
     image: gravitl/netmaker:v0.17.1
-    cap_add: 
-      - NET_ADMIN
-      - NET_RAW
-      - SYS_MODULE
-    sysctls:
-      - net.ipv4.ip_forward=1
-      - net.ipv4.conf.all.src_valid_mark=1
-      - net.ipv6.conf.all.disable_ipv6=0
-      - net.ipv6.conf.all.forwarding=1
     restart: always
     volumes: # Volume mounts necessary for sql, coredns, and mqtt
       - dnsconfig:/root/config/dnsconfig
@@ -26,11 +17,9 @@ services:
       COREDNS_ADDR: "SERVER_PUBLIC_IP" # Address of the CoreDNS server. Defaults to SERVER_HOST
       DNS_MODE: "on" # Enables DNS Mode, meaning all nodes will set hosts file for private dns settings.
       API_PORT: "8081" # The HTTP API port for Netmaker. Used for API calls / communication from front end. If changed, need to change port of BACKEND_URL for netmaker-ui.
-      CLIENT_MODE: "on" # Depricated. CLIENT_MODE should always be ON
       REST_BACKEND: "on" # Enables the REST backend (API running on API_PORT at SERVER_HTTP_HOST). Change to "off" to turn off.
       DISABLE_REMOTE_IP_CHECK: "off" # If turned "on", Server will not set Host based on remote IP check. This is already overridden if SERVER_HOST is set. Turned "off" by default.
       TELEMETRY: "on" # Whether or not to send telemetry data to help improve Netmaker. Switch to "off" to opt out of sending telemetry.
-      RCE: "off" # Enables setting PostUp and PostDown (arbitrary commands) on nodes from the server. Off by default.
       MASTER_KEY: "REPLACE_MASTER_KEY" # The admin master key for accessing the API. Change this in any production installation.
       CORS_ALLOWED_ORIGIN: "*" # The "allowed origin" for API requests. Change to restrict where API requests can come from with comma-separated URLs. ex:- https://dashboard.netmaker.domain1.com,https://dashboard.netmaker.domain2.com
       DISPLAY_KEYS: "on" # Show keys permanently in UI (until deleted) as opposed to 1-time display.
@@ -39,10 +28,7 @@ services:
       MQ_HOST: "mq"  # the address of the mq server. If running from docker compose it will be "mq". Otherwise, need to input address. If using "host networking", it will find and detect the IP of the mq container.
       MQ_SERVER_PORT: "1883" # the reachable port of MQ by the server - change if internal MQ port changes (or use external port if MQ is not on the same machine)
       MQ_PORT: "443" # the reachable port of MQ - change if external MQ port changes (port on proxy, not necessarily the one exposed in docker-compose)
-      HOST_NETWORK: "off" # whether or not host networking is turned on. Only turn on if configured for host networking (see docker-compose.hostnetwork.yml). Will set host-level settings like iptables.
       VERBOSITY: "1" # logging verbosity level - 1, 2, or 3
-      MANAGE_IPTABLES: "on" # deprecated
-      PORT_FORWARD_SERVICES: "dns" # decide which services to port forward ("dns","ssh", or "mq")
       # this section is for OAuth
       AUTH_PROVIDER: "" # "<azure-ad|github|google|oidc>"
       CLIENT_ID: "" # "<client id of your oauth provider>"

+ 0 - 11
compose/docker-compose.yml

@@ -4,15 +4,6 @@ services:
   netmaker:
     container_name: netmaker
     image: gravitl/netmaker:v0.17.1
-    cap_add: 
-      - NET_ADMIN
-      - NET_RAW
-      - SYS_MODULE
-    sysctls:
-      - net.ipv4.ip_forward=1
-      - net.ipv4.conf.all.src_valid_mark=1
-      - net.ipv6.conf.all.disable_ipv6=0
-      - net.ipv6.conf.all.forwarding=1
     restart: always
     volumes:
       - dnsconfig:/root/config/dnsconfig
@@ -27,7 +18,6 @@ services:
       DNS_MODE: "on"
       SERVER_HTTP_HOST: "api.NETMAKER_BASE_DOMAIN"
       API_PORT: "8081"
-      CLIENT_MODE: "on"
       MASTER_KEY: "REPLACE_MASTER_KEY"
       CORS_ALLOWED_ORIGIN: "*"
       DISPLAY_KEYS: "on"
@@ -36,7 +26,6 @@ services:
       MQ_HOST: "mq"
       MQ_PORT: "443"
       MQ_SERVER_PORT: "1883"
-      HOST_NETWORK: "off"
       VERBOSITY: "1"
       MANAGE_IPTABLES: "on"
       PORT_FORWARD_SERVICES: "dns"

+ 0 - 3
config/config.go

@@ -61,10 +61,7 @@ type ServerConfig struct {
 	FrontendURL           string `yaml:"frontendurl"`
 	DisplayKeys           string `yaml:"displaykeys"`
 	AzureTenant           string `yaml:"azuretenant"`
-	RCE                   string `yaml:"rce"`
 	Telemetry             string `yaml:"telemetry"`
-	ManageIPTables        string `yaml:"manageiptables"`
-	PortForwardServices   string `yaml:"portforwardservices"`
 	HostNetwork           string `yaml:"hostnetwork"`
 	MQPort                string `yaml:"mqport"`
 	MQServerPort          string `yaml:"mqserverport"`

+ 1 - 17
controllers/dns.go

@@ -160,7 +160,7 @@ func createDNS(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	entry, err = CreateDNS(entry)
+	entry, err = logic.CreateDNS(entry)
 	if err != nil {
 		logger.Log(0, r.Header.Get("user"),
 			fmt.Sprintf("Failed to create DNS entry %+v: %v", entry, err))
@@ -223,22 +223,6 @@ func deleteDNS(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(entrytext + " deleted.")
 }
 
-// CreateDNS - creates a DNS entry
-func CreateDNS(entry models.DNSEntry) (models.DNSEntry, error) {
-
-	data, err := json.Marshal(&entry)
-	if err != nil {
-		return models.DNSEntry{}, err
-	}
-	key, err := logic.GetRecordKey(entry.Name, entry.Network)
-	if err != nil {
-		return models.DNSEntry{}, err
-	}
-	err = database.Insert(key, string(data), database.DNS_TABLE_NAME)
-
-	return entry, err
-}
-
 // GetDNSEntry - gets a DNS entry
 func GetDNSEntry(domain string, network string) (models.DNSEntry, error) {
 	var entry models.DNSEntry

+ 67 - 49
controllers/dns_test.go

@@ -1,35 +1,45 @@
 package controller
 
 import (
+	"net"
 	"os"
 	"testing"
 
+	"github.com/google/uuid"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
 	"github.com/stretchr/testify/assert"
+	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 
+var dnsHost models.Host
+
 func TestGetAllDNS(t *testing.T) {
 	database.InitializeDatabase()
 	deleteAllDNS(t)
 	deleteAllNetworks()
 	createNet()
+	createHost()
 	t.Run("NoEntries", func(t *testing.T) {
 		entries, err := logic.GetAllDNS()
 		assert.Nil(t, err)
 		assert.Equal(t, []models.DNSEntry(nil), entries)
 	})
 	t.Run("OneEntry", func(t *testing.T) {
-		entry := models.DNSEntry{"10.0.0.3", "", "newhost", "skynet"}
-		CreateDNS(entry)
+		entry := models.DNSEntry{
+			"10.0.0.3", "", "newhost", "skynet",
+		}
+		_, err := logic.CreateDNS(entry)
+		assert.Nil(t, err)
 		entries, err := logic.GetAllDNS()
 		assert.Nil(t, err)
 		assert.Equal(t, 1, len(entries))
 	})
 	t.Run("MultipleEntry", func(t *testing.T) {
 		entry := models.DNSEntry{"10.0.0.7", "", "anotherhost", "skynet"}
-		CreateDNS(entry)
+		_, err := logic.CreateDNS(entry)
+		assert.Nil(t, err)
 		entries, err := logic.GetAllDNS()
 		assert.Nil(t, err)
 		assert.Equal(t, 2, len(entries))
@@ -41,22 +51,42 @@ func TestGetNodeDNS(t *testing.T) {
 	deleteAllDNS(t)
 	deleteAllNetworks()
 	createNet()
+	createHost()
 	t.Run("NoNodes", func(t *testing.T) {
 		dns, err := logic.GetNodeDNS("skynet")
 		assert.EqualError(t, err, "could not find any records")
 		assert.Equal(t, []models.DNSEntry(nil), dns)
 	})
 	t.Run("NodeExists", func(t *testing.T) {
-		createnode := models.Node{PublicKey: "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Name: "testnode", Endpoint: "10.0.0.1", MacAddress: "01:02:03:04:05:06", Password: "password", Network: "skynet", OS: "linux", DNSOn: "yes"}
-		err := logic.CreateNode(&createnode)
+		createHost()
+		_, ipnet, _ := net.ParseCIDR("10.0.0.1/32")
+		tmpCNode := models.CommonNode{
+			ID:      uuid.New(),
+			Network: "skynet",
+			Address: *ipnet,
+			DNSOn:   true,
+		}
+		createnode := models.Node{
+			CommonNode: tmpCNode,
+		}
+		err := logic.AssociateNodeToHost(&createnode, &dnsHost)
 		assert.Nil(t, err)
 		dns, err := logic.GetNodeDNS("skynet")
 		assert.Nil(t, err)
 		assert.Equal(t, "10.0.0.1", dns[0].Address)
 	})
 	t.Run("MultipleNodes", func(t *testing.T) {
-		createnode := &models.LegacyNode{PublicKey: "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Endpoint: "10.100.100.3", MacAddress: "01:02:03:04:05:07", Password: "password", Network: "skynet"}
-		err := logic.CreateNode(createnode)
+		_, ipnet, _ := net.ParseCIDR("10.100.100.3/32")
+		tmpCNode := models.CommonNode{
+			ID:      uuid.New(),
+			Network: "skynet",
+			Address: *ipnet,
+			DNSOn:   true,
+		}
+		createnode := models.Node{
+			CommonNode: tmpCNode,
+		}
+		err := logic.AssociateNodeToHost(&createnode, &dnsHost)
 		assert.Nil(t, err)
 		dns, err := logic.GetNodeDNS("skynet")
 		assert.Nil(t, err)
@@ -85,15 +115,17 @@ func TestGetCustomDNS(t *testing.T) {
 		assert.Equal(t, 0, len(dns))
 	})
 	t.Run("EntryExist", func(t *testing.T) {
-		entry := models.DNSEntry{"10.0.0.3", "", "newhost", "skynet"}
-		CreateDNS(entry)
+		entry := models.DNSEntry{"10.0.0.3", "", "custom1", "skynet"}
+		_, err := logic.CreateDNS(entry)
+		assert.Nil(t, err)
 		dns, err := logic.GetCustomDNS("skynet")
 		assert.Nil(t, err)
 		assert.Equal(t, 1, len(dns))
 	})
 	t.Run("MultipleEntries", func(t *testing.T) {
 		entry := models.DNSEntry{"10.0.0.4", "", "host4", "skynet"}
-		CreateDNS(entry)
+		_, err := logic.CreateDNS(entry)
+		assert.Nil(t, err)
 		dns, err := logic.GetCustomDNS("skynet")
 		assert.Nil(t, err)
 		assert.Equal(t, 2, len(dns))
@@ -112,7 +144,7 @@ func TestGetDNSEntryNum(t *testing.T) {
 	})
 	t.Run("NodeExists", func(t *testing.T) {
 		entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"}
-		_, err := CreateDNS(entry)
+		_, err := logic.CreateDNS(entry)
 		assert.Nil(t, err)
 		num, err := logic.GetDNSEntryNum("newhost", "skynet")
 		assert.Nil(t, err)
@@ -131,7 +163,7 @@ func TestGetDNS(t *testing.T) {
 	})
 	t.Run("CustomDNSExists", func(t *testing.T) {
 		entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"}
-		_, err := CreateDNS(entry)
+		_, err := logic.CreateDNS(entry)
 		assert.Nil(t, err)
 		dns, err := logic.GetDNS("skynet")
 		t.Log(dns)
@@ -151,7 +183,7 @@ func TestGetDNS(t *testing.T) {
 	})
 	t.Run("NodeAndCustomDNS", func(t *testing.T) {
 		entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"}
-		_, err := CreateDNS(entry)
+		_, err := logic.CreateDNS(entry)
 		assert.Nil(t, err)
 		dns, err := logic.GetDNS("skynet")
 		t.Log(dns)
@@ -169,7 +201,7 @@ func TestCreateDNS(t *testing.T) {
 	deleteAllNetworks()
 	createNet()
 	entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"}
-	dns, err := CreateDNS(entry)
+	dns, err := logic.CreateDNS(entry)
 	assert.Nil(t, err)
 	assert.Equal(t, "newhost", dns.Name)
 }
@@ -204,12 +236,13 @@ func TestSetDNS(t *testing.T) {
 		assert.False(t, info.IsDir())
 		content, err := os.ReadFile("./config/dnsconfig/netmaker.hosts")
 		assert.Nil(t, err)
-		assert.Contains(t, string(content), "testnode.skynet")
+		assert.Contains(t, string(content), "linuxhost.skynet")
 	})
 	t.Run("EntryExists", func(t *testing.T) {
 		entry := models.DNSEntry{"10.0.0.3", "", "newhost", "skynet"}
-		CreateDNS(entry)
-		err := logic.SetDNS()
+		_, err := logic.CreateDNS(entry)
+		assert.Nil(t, err)
+		err = logic.SetDNS()
 		assert.Nil(t, err)
 		info, err := os.Stat("./config/dnsconfig/netmaker.hosts")
 		assert.Nil(t, err)
@@ -228,7 +261,7 @@ func TestGetDNSEntry(t *testing.T) {
 	createNet()
 	createTestNode()
 	entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"}
-	CreateDNS(entry)
+	_, _ = logic.CreateDNS(entry)
 	t.Run("wrong net", func(t *testing.T) {
 		entry, err := GetDNSEntry("newhost", "w286 Toronto Street South, Uxbridge, ONirecat")
 		assert.EqualError(t, err, "no result found")
@@ -251,40 +284,13 @@ func TestGetDNSEntry(t *testing.T) {
 	})
 }
 
-//	func TestUpdateDNS(t *testing.T) {
-//		var newentry models.DNSEntry
-//		database.InitializeDatabase()
-//		deleteAllDNS(t)
-//		deleteAllNetworks()
-//		createNet()
-//		entry := models.DNSEntry{"10.0.0.2", "newhost", "skynet"}
-//		CreateDNS(entry)
-//		t.Run("change address", func(t *testing.T) {
-//			newentry.Address = "10.0.0.75"
-//			updated, err := UpdateDNS(newentry, entry)
-//			assert.Nil(t, err)
-//			assert.Equal(t, newentry.Address, updated.Address)
-//		})
-//		t.Run("change name", func(t *testing.T) {
-//			newentry.Name = "newname"
-//			updated, err := UpdateDNS(newentry, entry)
-//			assert.Nil(t, err)
-//			assert.Equal(t, newentry.Name, updated.Name)
-//		})
-//		t.Run("change network", func(t *testing.T) {
-//			newentry.Network = "wirecat"
-//			updated, err := UpdateDNS(newentry, entry)
-//			assert.Nil(t, err)
-//			assert.NotEqual(t, newentry.Network, updated.Network)
-//		})
-//	}
 func TestDeleteDNS(t *testing.T) {
 	database.InitializeDatabase()
 	deleteAllDNS(t)
 	deleteAllNetworks()
 	createNet()
 	entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"}
-	CreateDNS(entry)
+	_, _ = logic.CreateDNS(entry)
 	t.Run("EntryExists", func(t *testing.T) {
 		err := logic.DeleteDNS("newhost", "skynet")
 		assert.Nil(t, err)
@@ -351,8 +357,8 @@ func TestValidateDNSUpdate(t *testing.T) {
 	})
 	t.Run("NameUnique", func(t *testing.T) {
 		change := models.DNSEntry{"10.0.0.2", "", "myhost", "wirecat"}
-		CreateDNS(entry)
-		CreateDNS(change)
+		_, _ = logic.CreateDNS(entry)
+		_, _ = logic.CreateDNS(change)
 		err := logic.ValidateDNSUpdate(change, entry)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'name_unique' tag")
@@ -401,13 +407,25 @@ func TestValidateDNSCreate(t *testing.T) {
 	})
 	t.Run("NameUnique", func(t *testing.T) {
 		entry := models.DNSEntry{"10.0.0.2", "", "myhost", "skynet"}
-		_, _ = CreateDNS(entry)
+		_, _ = logic.CreateDNS(entry)
 		err := logic.ValidateDNSCreate(entry)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'name_unique' tag")
 	})
 }
 
+func createHost() {
+	k, _ := wgtypes.ParseKey("DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=")
+	dnsHost = models.Host{
+		ID:        uuid.New(),
+		PublicKey: k.PublicKey(),
+		HostPass:  "password",
+		OS:        "linux",
+		Name:      "dnshost",
+	}
+	_ = logic.CreateHost(&dnsHost)
+}
+
 func deleteAllDNS(t *testing.T) {
 	dns, err := logic.GetAllDNS()
 	assert.Nil(t, err)

+ 126 - 5
controllers/hosts.go

@@ -12,12 +12,9 @@ import (
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/mq"
+	"golang.org/x/crypto/bcrypt"
 )
 
-type hostNetworksUpdatePayload struct {
-	Networks []string `json:"networks"`
-}
-
 func hostHandlers(r *mux.Router) {
 	r.HandleFunc("/api/hosts", logic.SecurityCheck(true, http.HandlerFunc(getHosts))).Methods(http.MethodGet)
 	r.HandleFunc("/api/hosts/{hostid}", logic.SecurityCheck(true, http.HandlerFunc(updateHost))).Methods(http.MethodPut)
@@ -26,6 +23,7 @@ func hostHandlers(r *mux.Router) {
 	r.HandleFunc("/api/hosts/{hostid}/networks/{network}", logic.SecurityCheck(true, http.HandlerFunc(deleteHostFromNetwork))).Methods(http.MethodDelete)
 	r.HandleFunc("/api/hosts/{hostid}/relay", logic.SecurityCheck(false, http.HandlerFunc(createHostRelay))).Methods(http.MethodPost)
 	r.HandleFunc("/api/hosts/{hostid}/relay", logic.SecurityCheck(false, http.HandlerFunc(deleteHostRelay))).Methods(http.MethodDelete)
+	r.HandleFunc("/api/hosts/adm/authenticate", authenticateHost).Methods(http.MethodPost)
 }
 
 // swagger:route GET /api/hosts hosts getHosts
@@ -99,6 +97,10 @@ func updateHost(w http.ResponseWriter, r *http.Request) {
 	if updateRelay {
 		logic.UpdateHostRelay(currHost.ID.String(), currHost.RelayedHosts, newHost.RelayedHosts)
 	}
+<<<<<<< HEAD
+=======
+
+>>>>>>> f4851937c1746475fdac99e9c562623128ba16b1
 	// publish host update through MQ
 	if err := mq.HostUpdate(&models.HostUpdate{
 		Action: models.UpdateHost,
@@ -139,7 +141,33 @@ func deleteHost(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
-
+	if currHost.IsRelay {
+		if _, _, err := logic.DeleteHostRelay(hostid); err != nil {
+			logger.Log(0, r.Header.Get("user"), "failed to dissociate host from relays:", err.Error())
+			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+			return
+		}
+	}
+	if currHost.IsRelayed {
+		relayHost, err := logic.GetHost(currHost.RelayedBy)
+		if err != nil {
+			logger.Log(0, r.Header.Get("user"), "failed to fetch relay host:", err.Error())
+			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+			return
+		}
+		newRelayedHosts := make([]string, 0)
+		for _, relayedHostID := range relayHost.RelayedHosts {
+			if relayedHostID != hostid {
+				newRelayedHosts = append(newRelayedHosts, relayedHostID)
+			}
+		}
+		relayHost.RelayedHosts = newRelayedHosts
+		if err := logic.UpsertHost(relayHost); err != nil {
+			logger.Log(0, r.Header.Get("user"), "failed to update host relays:", err.Error())
+			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+			return
+		}
+	}
 	if err = logic.RemoveHost(currHost); err != nil {
 		logger.Log(0, r.Header.Get("user"), "failed to delete a host:", err.Error())
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
@@ -254,3 +282,96 @@ func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
 	logger.Log(2, r.Header.Get("user"), fmt.Sprintf("removed host %s from network %s", currHost.Name, network))
 	w.WriteHeader(http.StatusOK)
 }
+
+// swagger:route POST /api/hosts/adm/authenticate hosts authenticateHost
+//
+// Host based authentication for making further API calls.
+//
+//			Schemes: https
+//
+//			Security:
+//	  		oauth
+//
+//			Responses:
+//				200: successResponse
+func authenticateHost(response http.ResponseWriter, request *http.Request) {
+	var authRequest models.AuthParams
+	var errorResponse = models.ErrorResponse{
+		Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
+	}
+
+	decoder := json.NewDecoder(request.Body)
+	decoderErr := decoder.Decode(&authRequest)
+	defer request.Body.Close()
+
+	if decoderErr != nil {
+		errorResponse.Code = http.StatusBadRequest
+		errorResponse.Message = decoderErr.Error()
+		logger.Log(0, request.Header.Get("user"), "error decoding request body: ",
+			decoderErr.Error())
+		logic.ReturnErrorResponse(response, request, errorResponse)
+		return
+	}
+	errorResponse.Code = http.StatusBadRequest
+	if authRequest.ID == "" {
+		errorResponse.Message = "W1R3: ID can't be empty"
+		logger.Log(0, request.Header.Get("user"), errorResponse.Message)
+		logic.ReturnErrorResponse(response, request, errorResponse)
+		return
+	} else if authRequest.Password == "" {
+		errorResponse.Message = "W1R3: Password can't be empty"
+		logger.Log(0, request.Header.Get("user"), errorResponse.Message)
+		logic.ReturnErrorResponse(response, request, errorResponse)
+		return
+	}
+	host, err := logic.GetHost(authRequest.ID)
+	if err != nil {
+		errorResponse.Code = http.StatusBadRequest
+		errorResponse.Message = err.Error()
+		logger.Log(0, request.Header.Get("user"),
+			"error retrieving host: ", err.Error())
+		logic.ReturnErrorResponse(response, request, errorResponse)
+		return
+	}
+	err = bcrypt.CompareHashAndPassword([]byte(host.HostPass), []byte(authRequest.Password))
+	if err != nil {
+		errorResponse.Code = http.StatusUnauthorized
+		errorResponse.Message = "unauthorized"
+		logger.Log(0, request.Header.Get("user"),
+			"error validating user password: ", err.Error())
+		logic.ReturnErrorResponse(response, request, errorResponse)
+		return
+	}
+
+	tokenString, err := logic.CreateJWT(authRequest.ID, authRequest.MacAddress, "")
+	if tokenString == "" {
+		errorResponse.Code = http.StatusUnauthorized
+		errorResponse.Message = "unauthorized"
+		logger.Log(0, request.Header.Get("user"),
+			fmt.Sprintf("%s: %v", errorResponse.Message, err))
+		logic.ReturnErrorResponse(response, request, errorResponse)
+		return
+	}
+
+	var successResponse = models.SuccessResponse{
+		Code:    http.StatusOK,
+		Message: "W1R3: Host " + authRequest.ID + " Authorized",
+		Response: models.SuccessfulLoginResponse{
+			AuthToken: tokenString,
+			ID:        authRequest.ID,
+		},
+	}
+	successJSONResponse, jsonError := json.Marshal(successResponse)
+
+	if jsonError != nil {
+		errorResponse.Code = http.StatusBadRequest
+		errorResponse.Message = err.Error()
+		logger.Log(0, request.Header.Get("user"),
+			"error marshalling resp: ", err.Error())
+		logic.ReturnErrorResponse(response, request, errorResponse)
+		return
+	}
+	response.WriteHeader(http.StatusOK)
+	response.Header().Set("Content-Type", "application/json")
+	response.Write(successJSONResponse)
+}

+ 78 - 0
controllers/migrate.go

@@ -0,0 +1,78 @@
+package controller
+
+import (
+	"encoding/json"
+	"io"
+	"net/http"
+	"strings"
+
+	"github.com/gorilla/mux"
+	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/logger"
+	"github.com/gravitl/netmaker/logic"
+	"github.com/gravitl/netmaker/models"
+	"golang.org/x/crypto/bcrypt"
+)
+
+// swagger:route PUT /api/nodes/{network}/{nodeid}/migrate nodes migrateNode
+//
+// Used to migrate a legacy node.
+//
+//			Schemes: https
+//
+//			Security:
+//	  		oauth
+//
+//			Responses:
+//				200: nodeJoinResponse
+func migrate(w http.ResponseWriter, r *http.Request) {
+	// we decode our body request params
+	data := models.MigrationData{}
+	err := json.NewDecoder(r.Body).Decode(&data)
+	if err != nil {
+		logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error())
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+		return
+	}
+	params := mux.Vars(r)
+	//check authorization
+	record, err := database.FetchRecord(database.NODES_TABLE_NAME, data.LegacyNodeID)
+	if err != nil {
+		logger.Log(0, "no record for legacy node", data.LegacyNodeID, err.Error())
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+		return
+	}
+	var legacyNode models.LegacyNode
+	if err = json.Unmarshal([]byte(record), &legacyNode); err != nil {
+		logger.Log(0, "error decoding legacy node", err.Error())
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+		return
+	}
+	if err := bcrypt.CompareHashAndPassword([]byte(legacyNode.Password), []byte(data.Password)); err != nil {
+		logger.Log(0, "error decoding legacy password", err.Error())
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "unauthorized"))
+		return
+	}
+	network, err := logic.GetNetwork(params["network"])
+	if err != nil {
+		logger.Log(0, "error retrieving network:  ", err.Error())
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+		return
+	}
+	key, err := logic.CreateAccessKey(models.AccessKey{}, network)
+	if err != nil {
+		logger.Log(0, "error creating key:  ", err.Error())
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+		return
+	}
+	data.JoinData.Key = key.Value
+	payload, err := json.Marshal(data.JoinData)
+	if err != nil {
+		logger.Log(0, "error encoding data:  ", err.Error())
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+		return
+	}
+	r.Body = io.NopCloser(strings.NewReader(string(payload)))
+	r.ContentLength = int64(len(string(payload)))
+	createNode(w, r)
+}

+ 2 - 18
controllers/network.go

@@ -185,13 +185,7 @@ func updateNetwork(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 		return
 	}
-
-	if !servercfg.GetRce() {
-		newNetwork.DefaultPostDown = network.DefaultPostDown
-		newNetwork.DefaultPostUp = network.DefaultPostUp
-	}
-
-	rangeupdate4, rangeupdate6, localrangeupdate, holepunchupdate, groupsDelta, userDelta, err := logic.UpdateNetwork(&network, &newNetwork)
+	rangeupdate4, rangeupdate6, holepunchupdate, groupsDelta, userDelta, err := logic.UpdateNetwork(&network, &newNetwork)
 	if err != nil {
 		logger.Log(0, r.Header.Get("user"), "failed to update network: ",
 			err.Error())
@@ -237,17 +231,7 @@ func updateNetwork(w http.ResponseWriter, r *http.Request) {
 			return
 		}
 	}
-	if localrangeupdate {
-		err = logic.UpdateNetworkLocalAddresses(network.NetID)
-		if err != nil {
-			logger.Log(0, r.Header.Get("user"),
-				fmt.Sprintf("failed to update network [%s] local addresses: %v",
-					network.NetID, err.Error()))
-			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
-			return
-		}
-	}
-	if rangeupdate4 || rangeupdate6 || localrangeupdate || holepunchupdate {
+	if rangeupdate4 || rangeupdate6 || holepunchupdate {
 		nodes, err := logic.GetNetworkNodes(network.NetID)
 		if err != nil {
 			logger.Log(0, r.Header.Get("user"),

+ 20 - 11
controllers/network_test.go

@@ -4,10 +4,12 @@ import (
 	"os"
 	"testing"
 
+	"github.com/google/uuid"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
 	"github.com/stretchr/testify/assert"
+	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 
 type NetworkValidationTestCase struct {
@@ -16,6 +18,8 @@ type NetworkValidationTestCase struct {
 	errMessage string
 }
 
+var netHost models.Host
+
 func TestCreateNetwork(t *testing.T) {
 	initialize()
 	deleteAllNetworks()
@@ -271,14 +275,6 @@ func TestValidateNetwork(t *testing.T) {
 			},
 			errMessage: "Field validation for 'DefaultKeepalive' failed on the 'max' tag",
 		},
-		{
-			testname: "InvalidLocalRange",
-			network: models.Network{
-				NetID:      "skynet",
-				LocalRange: "192.168.0.1",
-			},
-			errMessage: "Field validation for 'LocalRange' failed on the 'cidr' tag",
-		},
 	}
 	for _, tc := range cases {
 		t.Run(tc.testname, func(t *testing.T) {
@@ -305,11 +301,12 @@ func TestIpv6Network(t *testing.T) {
 		assert.Nil(t, err)
 		assert.Equal(t, network.AddressRange6, "fde6:be04:fa5e:d076::/64")
 	})
-	node1 := models.LegacyNode{PublicKey: "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Name: "testnode", Endpoint: "10.0.0.50", MacAddress: "01:02:03:04:05:06", Password: "password", Network: "skynet6", OS: "linux"}
-	nodeErr := logic.CreateNode(&node1)
+	node1 := createNodeWithParams("skynet6", "")
+	createNetHost()
+	nodeErr := logic.AssociateNodeToHost(node1, &netHost)
 	t.Run("Test node on network IPv6", func(t *testing.T) {
 		assert.Nil(t, nodeErr)
-		assert.Equal(t, "fde6:be04:fa5e:d076::1", node1.Address6)
+		assert.Equal(t, "fde6:be04:fa5e:d076::1", node1.Address6.IP.String())
 	})
 }
 
@@ -358,3 +355,15 @@ func createNetDualStack() {
 		logic.CreateNetwork(network)
 	}
 }
+
+func createNetHost() {
+	k, _ := wgtypes.ParseKey("DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=")
+	netHost = models.Host{
+		ID:        uuid.New(),
+		PublicKey: k.PublicKey(),
+		HostPass:  "password",
+		OS:        "linux",
+		Name:      "nethost",
+	}
+	_ = logic.CreateHost(&netHost)
+}

+ 66 - 104
controllers/node.go

@@ -4,7 +4,6 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
-	"io"
 	"net/http"
 	"strings"
 
@@ -26,7 +25,7 @@ func nodeHandlers(r *mux.Router) {
 	r.HandleFunc("/api/nodes/{network}", authorize(false, true, "network", http.HandlerFunc(getNetworkNodes))).Methods(http.MethodGet)
 	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}/migrate", authorize(true, true, "node", http.HandlerFunc(migrate))).Methods(http.MethodPut)
+	r.HandleFunc("/api/nodes/{network}/{nodeid}/migrate", migrate).Methods(http.MethodPost)
 	r.HandleFunc("/api/nodes/{network}/{nodeid}", authorize(true, true, "node", http.HandlerFunc(deleteNode))).Methods(http.MethodDelete)
 	r.HandleFunc("/api/nodes/{network}/{nodeid}/createrelay", authorize(false, true, "user", http.HandlerFunc(createRelay))).Methods(http.MethodPost)
 	r.HandleFunc("/api/nodes/{network}/{nodeid}/deleterelay", authorize(false, true, "user", http.HandlerFunc(deleteRelay))).Methods(http.MethodDelete)
@@ -188,6 +187,7 @@ func nodeauth(next http.Handler) http.HandlerFunc {
 			logic.ReturnErrorResponse(w, r, errorResponse)
 			return
 		}
+
 		next.ServeHTTP(w, r)
 	}
 }
@@ -524,7 +524,7 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 	}
 
 	if !logic.IsVersionComptatible(data.Host.Version) {
-		err := errors.New("incomatible netclient version")
+		err := errors.New("incompatible netclient version")
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 		return
 	}
@@ -550,6 +550,7 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, errorResponse)
 		return
 	}
+	logic.DecrimentKey(networkName, data.Key)
 	user, err := pro.GetNetworkUser(networkName, promodels.NetworkUserID(keyName))
 	if err == nil {
 		if user.ID != "" {
@@ -577,6 +578,9 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 	server := servercfg.GetServerInfo()
 	server.TrafficKey = key
 	data.Node.Server = servercfg.GetServer()
+	if !logic.HostExists(&data.Host) {
+		logic.CheckHostPorts(&data.Host)
+	}
 	if err := logic.CreateHost(&data.Host); err != nil {
 		if errors.Is(err, logic.ErrHostExists) {
 			logger.Log(3, "host exists .. no need to create")
@@ -586,8 +590,15 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 				logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 				return
 			}
-			logic.UpdateHost(&data.Host, host) // update the in memory struct values
-
+			logic.UpdateHostFromClient(&data.Host, host) // update the in memory struct values
+			err = logic.UpsertHost(host)
+			if err != nil {
+				logger.Log(0, r.Header.Get("user"),
+					fmt.Sprintf("failed to update host [ %s ]: %v", host.ID.String(), err))
+				logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+				return
+			}
+			data.Host = *host
 		} else {
 			logger.Log(0, "error creating host", err.Error())
 			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
@@ -628,6 +639,8 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
+	data.Host.HostPass = "" // client should not change password after join
+	// concealing hash
 	response := models.NodeJoinResponse{
 		Node:         data.Node,
 		ServerConfig: server,
@@ -660,32 +673,33 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 //			Responses:
 //				200: nodeResponse
 func createEgressGateway(w http.ResponseWriter, r *http.Request) {
-	var gateway models.EgressGatewayRequest
-	var params = mux.Vars(r)
-	w.Header().Set("Content-Type", "application/json")
-	err := json.NewDecoder(r.Body).Decode(&gateway)
-	if err != nil {
-		logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error())
-		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
-		return
-	}
-	gateway.NetID = params["network"]
-	gateway.NodeID = params["nodeid"]
-	node, err := logic.CreateEgressGateway(gateway)
-	if err != nil {
-		logger.Log(0, r.Header.Get("user"),
-			fmt.Sprintf("failed to create egress gateway on node [%s] on network [%s]: %v",
-				gateway.NodeID, gateway.NetID, err))
-		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
-		return
-	}
-
-	apiNode := node.ConvertToAPINode()
-	logger.Log(1, r.Header.Get("user"), "created egress gateway on node", gateway.NodeID, "on network", gateway.NetID)
-	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(apiNode)
-
-	runUpdates(&node, true)
+	logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("currently unimplemented"), "internal"))
+	// var gateway models.EgressGatewayRequest
+	// var params = mux.Vars(r)
+	// w.Header().Set("Content-Type", "application/json")
+	// err := json.NewDecoder(r.Body).Decode(&gateway)
+	//	if err != nil {
+	//		logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error())
+	//		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+	//		return
+	//	}
+	// gateway.NetID = params["network"]
+	// gateway.NodeID = params["nodeid"]
+	// node, err := logic.CreateEgressGateway(gateway)
+	//	if err != nil {
+	//		logger.Log(0, r.Header.Get("user"),
+	//			fmt.Sprintf("failed to create egress gateway on node [%s] on network [%s]: %v",
+	//				gateway.NodeID, gateway.NetID, err))
+	//		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+	//		return
+	//	}
+	//
+	// apiNode := node.ConvertToAPINode()
+	// logger.Log(1, r.Header.Get("user"), "created egress gateway on node", gateway.NodeID, "on network", gateway.NetID)
+	// w.WriteHeader(http.StatusOK)
+	// json.NewEncoder(w).Encode(apiNode)
+	//
+	// runUpdates(&node, true)
 }
 
 // swagger:route DELETE /api/nodes/{network}/{nodeid}/deletegateway nodes deleteEgressGateway
@@ -700,25 +714,26 @@ func createEgressGateway(w http.ResponseWriter, r *http.Request) {
 //			Responses:
 //				200: nodeResponse
 func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
-	w.Header().Set("Content-Type", "application/json")
-	var params = mux.Vars(r)
-	nodeid := params["nodeid"]
-	netid := params["network"]
-	node, err := logic.DeleteEgressGateway(netid, nodeid)
-	if err != nil {
-		logger.Log(0, r.Header.Get("user"),
-			fmt.Sprintf("failed to delete egress gateway on node [%s] on network [%s]: %v",
-				nodeid, netid, err))
-		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
-		return
-	}
-
-	apiNode := node.ConvertToAPINode()
-	logger.Log(1, r.Header.Get("user"), "deleted egress gateway on node", nodeid, "on network", netid)
-	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(apiNode)
-
-	runUpdates(&node, true)
+	logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("currently unimplemented"), "internal"))
+	//w.Header().Set("Content-Type", "application/json")
+	// var params = mux.Vars(r)
+	// nodeid := params["nodeid"]
+	// netid := params["network"]
+	// node, err := logic.DeleteEgressGateway(netid, nodeid)
+	//	if err != nil {
+	//		logger.Log(0, r.Header.Get("user"),
+	//			fmt.Sprintf("failed to delete egress gateway on node [%s] on network [%s]: %v",
+	//				nodeid, netid, err))
+	//		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+	//		return
+	//	}
+	//
+	// apiNode := node.ConvertToAPINode()
+	// logger.Log(1, r.Header.Get("user"), "deleted egress gateway on node", nodeid, "on network", netid)
+	// w.WriteHeader(http.StatusOK)
+	// json.NewEncoder(w).Encode(apiNode)
+	//
+	// runUpdates(&node, true)
 }
 
 // == INGRESS ==
@@ -807,51 +822,6 @@ func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
 	runUpdates(&node, true)
 }
 
-// swagger:route PUT /api/nodes/{network}/{nodeid}/migrate nodes migrateNode
-//
-// Used to migrate a legacy node.
-//
-//			Schemes: https
-//
-//			Security:
-//	  		oauth
-//
-//			Responses:
-//				200: nodeJoinResponse
-func migrate(w http.ResponseWriter, r *http.Request) {
-	// we decode our body request params
-	data := models.JoinData{}
-	err := json.NewDecoder(r.Body).Decode(&data)
-	if err != nil {
-		logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error())
-		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
-		return
-	}
-	params := mux.Vars(r)
-	network, err := logic.GetNetwork(params["network"])
-	if err != nil {
-		logger.Log(0, "error retrieving network:  ", err.Error())
-		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
-		return
-	}
-	key, err := logic.CreateAccessKey(models.AccessKey{}, network)
-	if err != nil {
-		logger.Log(0, "error creating key:  ", err.Error())
-		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
-		return
-	}
-	data.Key = key.Value
-	payload, err := json.Marshal(data)
-	if err != nil {
-		logger.Log(0, "error encoding data:  ", err.Error())
-		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
-		return
-	}
-	r.Body = io.NopCloser(strings.NewReader(string(payload)))
-	r.ContentLength = int64(len(string(payload)))
-	createNode(w, r)
-}
-
 // swagger:route PUT /api/nodes/{network}/{nodeid} nodes updateNode
 //
 // Update an individual node.
@@ -920,11 +890,6 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 	if currentNode.IsRelayed && (currentNode.Address.String() != newNode.Address.String() || currentNode.Address6.String() != newNode.Address6.String()) {
 		relayedUpdate = true
 	}
-
-	if !servercfg.GetRce() {
-		newNode.PostDown = currentNode.PostDown
-		newNode.PostUp = currentNode.PostUp
-	}
 	ifaceDelta := logic.IfaceDelta(&currentNode, newNode)
 
 	if ifaceDelta && servercfg.Is_EE {
@@ -988,7 +953,6 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 		return
 	}
-
 	if r.Header.Get("ismaster") != "yes" {
 		username := r.Header.Get("user")
 		if username != "" && !doesUserOwnNode(username, params["network"], nodeid) {
@@ -1002,9 +966,7 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
 	}
 	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
+	if !fromNode { // notify node change
 		runUpdates(&node, false)
 	}
 	go func() { // notify of peer change

+ 101 - 73
controllers/node_test.go

@@ -1,16 +1,22 @@
 package controller
 
 import (
+	"net"
 	"testing"
 
+	"github.com/google/uuid"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/logic/acls"
 	"github.com/gravitl/netmaker/logic/acls/nodeacls"
 	"github.com/gravitl/netmaker/models"
 	"github.com/stretchr/testify/assert"
+	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 
+var nonLinuxHost models.Host
+var linuxHost models.Host
+
 func TestCreateEgressGateway(t *testing.T) {
 	var gateway models.EgressGatewayRequest
 	gateway.Interface = "eth0"
@@ -21,45 +27,39 @@ func TestCreateEgressGateway(t *testing.T) {
 	createNet()
 	t.Run("NoNodes", func(t *testing.T) {
 		node, err := logic.CreateEgressGateway(gateway)
-		assert.Equal(t, models.LegacyNode{}, node)
+		assert.Equal(t, models.Node{}, node)
 		assert.EqualError(t, err, "could not find any records")
 	})
 	t.Run("Non-linux node", func(t *testing.T) {
-		createnode := models.LegacyNode{PublicKey: "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Name: "testnode", Endpoint: "10.0.0.1", MacAddress: "01:02:03:04:05:06", Password: "password", Network: "skynet", OS: "windows"}
-		err := logic.CreateNode(&createnode)
+		createnode := createNodeWithParams("", "")
+		createNodeHosts()
+		createnode.HostID = nonLinuxHost.ID
+		err := logic.AssociateNodeToHost(createnode, &nonLinuxHost)
 		assert.Nil(t, err)
-		gateway.NodeID = createnode.ID
+		gateway.NodeID = createnode.ID.String()
 		node, err := logic.CreateEgressGateway(gateway)
-		assert.Equal(t, models.LegacyNode{}, node)
+		assert.Equal(t, models.Node{}, node)
 		assert.EqualError(t, err, "windows is unsupported for egress gateways")
 	})
 	t.Run("Success-Nat-Enabled", func(t *testing.T) {
 		deleteAllNodes()
 		testnode := createTestNode()
-		gateway.NodeID = testnode.ID
+		gateway.NodeID = testnode.ID.String()
 		gateway.NatEnabled = "yes"
 
 		node, err := logic.CreateEgressGateway(gateway)
 		t.Log(node.EgressGatewayNatEnabled)
-		t.Log(node.PostUp)
-		t.Log(node.PostDown)
 		assert.Nil(t, err)
-		assert.Contains(t, node.PostUp, "-j MASQUERADE")
-		assert.Contains(t, node.PostDown, "-j MASQUERADE")
 	})
 	t.Run("Success-Nat-Disabled", func(t *testing.T) {
 		deleteAllNodes()
 		testnode := createTestNode()
-		gateway.NodeID = testnode.ID
+		gateway.NodeID = testnode.ID.String()
 		gateway.NatEnabled = "no"
 
 		node, err := logic.CreateEgressGateway(gateway)
 		t.Log(node.EgressGatewayNatEnabled)
-		t.Log(node.PostUp)
-		t.Log(node.PostDown)
 		assert.Nil(t, err)
-		assert.NotContains(t, node.PostUp, "-j MASUERADE")
-		assert.NotContains(t, node.PostDown, "-j MASUERADE")
 	})
 	t.Run("Success", func(t *testing.T) {
 		var gateway models.EgressGatewayRequest
@@ -68,14 +68,12 @@ func TestCreateEgressGateway(t *testing.T) {
 		gateway.NetID = "skynet"
 		deleteAllNodes()
 		testnode := createTestNode()
-		gateway.NodeID = testnode.ID
+		gateway.NodeID = testnode.ID.String()
 
 		node, err := logic.CreateEgressGateway(gateway)
 		t.Log(node)
 		assert.Nil(t, err)
-		assert.Contains(t, node.PostUp, "-j MASQUERADE")
-		assert.Contains(t, node.PostDown, "-j MASQUERADE")
-		assert.Equal(t, "yes", node.IsEgressGateway)
+		assert.Equal(t, true, node.IsEgressGateway)
 		assert.Equal(t, gateway.Ranges, node.EgressGatewayRanges)
 	})
 
@@ -89,31 +87,27 @@ func TestDeleteEgressGateway(t *testing.T) {
 	gateway.Interface = "eth0"
 	gateway.Ranges = []string{"10.100.100.0/24"}
 	gateway.NetID = "skynet"
-	gateway.NodeID = testnode.ID
+	gateway.NodeID = testnode.ID.String()
 	t.Run("Success", func(t *testing.T) {
 		node, err := logic.CreateEgressGateway(gateway)
 		assert.Nil(t, err)
-		assert.Equal(t, "yes", node.IsEgressGateway)
+		assert.Equal(t, true, node.IsEgressGateway)
 		assert.Equal(t, []string{"10.100.100.0/24"}, node.EgressGatewayRanges)
 		node, err = logic.DeleteEgressGateway(gateway.NetID, gateway.NodeID)
 		assert.Nil(t, err)
-		assert.Equal(t, "no", node.IsEgressGateway)
+		assert.Equal(t, false, node.IsEgressGateway)
 		assert.Equal(t, []string([]string{}), node.EgressGatewayRanges)
-		assert.Equal(t, "", node.PostUp)
-		assert.Equal(t, "", node.PostDown)
 	})
 	t.Run("NotGateway", func(t *testing.T) {
 		node, err := logic.DeleteEgressGateway(gateway.NetID, gateway.NodeID)
 		assert.Nil(t, err)
-		assert.Equal(t, "no", node.IsEgressGateway)
+		assert.Equal(t, false, node.IsEgressGateway)
 		assert.Equal(t, []string([]string{}), node.EgressGatewayRanges)
-		assert.Equal(t, "", node.PostUp)
-		assert.Equal(t, "", node.PostDown)
 	})
 	t.Run("BadNode", func(t *testing.T) {
 		node, err := logic.DeleteEgressGateway(gateway.NetID, "01:02:03")
 		assert.EqualError(t, err, "no result found")
-		assert.Equal(t, models.LegacyNode{}, node)
+		assert.Equal(t, models.Node{}, node)
 		deleteAllNodes()
 	})
 }
@@ -140,23 +134,7 @@ func TestGetNetworkNodes(t *testing.T) {
 	})
 
 }
-func TestUncordonNode(t *testing.T) {
-	database.InitializeDatabase()
-	deleteAllNetworks()
-	createNet()
-	node := createTestNode()
-	t.Run("BadID", func(t *testing.T) {
-		resp, err := logic.UncordonNode("blahblah")
-		assert.Equal(t, models.LegacyNode{}, resp)
-		assert.EqualError(t, err, "no result found")
-	})
-	t.Run("Success", func(t *testing.T) {
-		resp, err := logic.UncordonNode(node.ID)
-		assert.Nil(t, err)
-		assert.Equal(t, "no", resp.IsPending)
-	})
 
-}
 func TestValidateEgressGateway(t *testing.T) {
 	var gateway models.EgressGatewayRequest
 	t.Run("EmptyRange", func(t *testing.T) {
@@ -181,66 +159,73 @@ func TestValidateEgressGateway(t *testing.T) {
 
 func TestNodeACLs(t *testing.T) {
 	deleteAllNodes()
-	node1 := models.LegacyNode{PublicKey: "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Name: "testnode", Endpoint: "10.0.0.50", MacAddress: "01:02:03:04:05:06", Password: "password", Network: "skynet", OS: "linux"}
-	node2 := models.LegacyNode{PublicKey: "DM5qhLAE20FG7BbfBCger+Ac9D2NDOwCtY1rbYDXf14=", Name: "testnode", Endpoint: "10.0.0.100", MacAddress: "01:02:03:04:05:07", Password: "password", Network: "skynet", OS: "linux"}
-	logic.CreateNode(&node1)
-	logic.CreateNode(&node2)
+	node1 := createNodeWithParams("", "10.0.0.50/32")
+	node2 := createNodeWithParams("", "10.0.0.100/32")
+	logic.AssociateNodeToHost(node1, &linuxHost)
+	logic.AssociateNodeToHost(node2, &linuxHost)
 	t.Run("acls not present", func(t *testing.T) {
 		currentACL, err := nodeacls.FetchAllACLs(nodeacls.NetworkID(node1.Network))
 		assert.Nil(t, err)
 		assert.NotNil(t, currentACL)
-		node1ACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(node1.Network), nodeacls.NodeID(node1.ID))
+		node1ACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(node1.Network), nodeacls.NodeID(node1.ID.String()))
 		assert.Nil(t, err)
 		assert.NotNil(t, node1ACL)
-		assert.Equal(t, acls.Allowed, node1ACL[acls.AclID(node2.ID)])
+		assert.Equal(t, acls.Allowed, node1ACL[acls.AclID(node2.ID.String())])
 	})
 	t.Run("node acls exists after creates", func(t *testing.T) {
-		node1ACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(node1.Network), nodeacls.NodeID(node1.ID))
+		node1ACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(node1.Network), nodeacls.NodeID(node1.ID.String()))
 		assert.Nil(t, err)
 		assert.NotNil(t, node1ACL)
-		node2ACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(node2.Network), nodeacls.NodeID(node2.ID))
+		node2ACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(node2.Network), nodeacls.NodeID(node2.ID.String()))
 		assert.Nil(t, err)
 		assert.NotNil(t, node2ACL)
-		assert.Equal(t, acls.Allowed, node2ACL[acls.AclID(node1.ID)])
+		assert.Equal(t, acls.Allowed, node2ACL[acls.AclID(node1.ID.String())])
 	})
 	t.Run("node acls correct after fetch", func(t *testing.T) {
-		node1ACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(node1.Network), nodeacls.NodeID(node1.ID))
+		node1ACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(node1.Network), nodeacls.NodeID(node1.ID.String()))
 		assert.Nil(t, err)
-		assert.Equal(t, acls.Allowed, node1ACL[acls.AclID(node2.ID)])
+		assert.Equal(t, acls.Allowed, node1ACL[acls.AclID(node2.ID.String())])
 	})
 	t.Run("node acls correct after modify", func(t *testing.T) {
-		node1ACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(node1.Network), nodeacls.NodeID(node1.ID))
+		node1ACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(node1.Network), nodeacls.NodeID(node1.ID.String()))
 		assert.Nil(t, err)
 		assert.NotNil(t, node1ACL)
-		node2ACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(node2.Network), nodeacls.NodeID(node2.ID))
+		node2ACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(node2.Network), nodeacls.NodeID(node2.ID.String()))
 		assert.Nil(t, err)
 		assert.NotNil(t, node2ACL)
-		currentACL, err := nodeacls.DisallowNodes(nodeacls.NetworkID(node1.Network), nodeacls.NodeID(node1.ID), nodeacls.NodeID(node2.ID))
+		currentACL, err := nodeacls.DisallowNodes(nodeacls.NetworkID(node1.Network), nodeacls.NodeID(node1.ID.String()), nodeacls.NodeID(node2.ID.String()))
 		assert.Nil(t, err)
-		assert.Equal(t, acls.NotAllowed, currentACL[acls.AclID(node1.ID)][acls.AclID(node2.ID)])
-		assert.Equal(t, acls.NotAllowed, currentACL[acls.AclID(node2.ID)][acls.AclID(node1.ID)])
+		assert.Equal(t, acls.NotAllowed, currentACL[acls.AclID(node1.ID.String())][acls.AclID(node2.ID.String())])
+		assert.Equal(t, acls.NotAllowed, currentACL[acls.AclID(node2.ID.String())][acls.AclID(node1.ID.String())])
 		currentACL.Save(acls.ContainerID(node1.Network))
 	})
 	t.Run("node acls correct after add new node not allowed", func(t *testing.T) {
-		node3 := models.LegacyNode{PublicKey: "this-is-not-valid", Name: "testnode3", Endpoint: "10.0.0.100", MacAddress: "01:02:03:04:05:07", Password: "password", Network: "skynet", OS: "linux"}
-		logic.CreateNode(&node3)
-		var currentACL, err = nodeacls.FetchAllACLs(nodeacls.NetworkID(node3.Network))
+		node3 := createNodeWithParams("", "10.0.0.100/32")
+		createNodeHosts()
+		n, e := logic.GetNetwork(node3.Network)
+		assert.Nil(t, e)
+		n.DefaultACL = "no"
+		e = logic.SaveNetwork(&n)
+		assert.Nil(t, e)
+		err := logic.AssociateNodeToHost(node3, &linuxHost)
+		assert.Nil(t, err)
+		currentACL, err := nodeacls.FetchAllACLs(nodeacls.NetworkID(node3.Network))
 		assert.Nil(t, err)
 		assert.NotNil(t, currentACL)
-		assert.Equal(t, acls.NotPresent, currentACL[acls.AclID(node1.ID)][acls.AclID(node3.ID)])
-		nodeACL, err := nodeacls.CreateNodeACL(nodeacls.NetworkID(node3.Network), nodeacls.NodeID(node3.ID), acls.NotAllowed)
+		assert.Equal(t, acls.NotAllowed, currentACL[acls.AclID(node1.ID.String())][acls.AclID(node3.ID.String())])
+		nodeACL, err := nodeacls.CreateNodeACL(nodeacls.NetworkID(node3.Network), nodeacls.NodeID(node3.ID.String()), acls.NotAllowed)
 		assert.Nil(t, err)
-		nodeACL.Save(acls.ContainerID(node3.Network), acls.AclID(node3.ID))
+		nodeACL.Save(acls.ContainerID(node3.Network), acls.AclID(node3.ID.String()))
 		currentACL, err = nodeacls.FetchAllACLs(nodeacls.NetworkID(node3.Network))
 		assert.Nil(t, err)
-		assert.Equal(t, acls.NotAllowed, currentACL[acls.AclID(node1.ID)][acls.AclID(node3.ID)])
-		assert.Equal(t, acls.NotAllowed, currentACL[acls.AclID(node2.ID)][acls.AclID(node3.ID)])
+		assert.Equal(t, acls.NotAllowed, currentACL[acls.AclID(node1.ID.String())][acls.AclID(node3.ID.String())])
+		assert.Equal(t, acls.NotAllowed, currentACL[acls.AclID(node2.ID.String())][acls.AclID(node3.ID.String())])
 	})
 	t.Run("node acls removed", func(t *testing.T) {
-		retNetworkACL, err := nodeacls.RemoveNodeACL(nodeacls.NetworkID(node1.Network), nodeacls.NodeID(node1.ID))
+		retNetworkACL, err := nodeacls.RemoveNodeACL(nodeacls.NetworkID(node1.Network), nodeacls.NodeID(node1.ID.String()))
 		assert.Nil(t, err)
 		assert.NotNil(t, retNetworkACL)
-		assert.Equal(t, acls.NotPresent, retNetworkACL[acls.AclID(node2.ID)][acls.AclID(node1.ID)])
+		assert.Equal(t, acls.NotPresent, retNetworkACL[acls.AclID(node2.ID.String())][acls.AclID(node1.ID.String())])
 	})
 	deleteAllNodes()
 }
@@ -249,8 +234,51 @@ func deleteAllNodes() {
 	database.DeleteAllRecords(database.NODES_TABLE_NAME)
 }
 
-func createTestNode() *models.LegacyNode {
-	createnode := models.LegacyNode{PublicKey: "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Name: "testnode", Endpoint: "10.0.0.1", MacAddress: "01:02:03:04:05:06", Password: "password", Network: "skynet", OS: "linux"}
-	logic.CreateNode(&createnode)
+func createTestNode() *models.Node {
+	createNodeHosts()
+	n := createNodeWithParams("skynet", "")
+	_ = logic.AssociateNodeToHost(n, &linuxHost)
+	return n
+}
+
+func createNodeWithParams(network, address string) *models.Node {
+	_, ipnet, _ := net.ParseCIDR("10.0.0.1/32")
+	tmpCNode := models.CommonNode{
+		ID:      uuid.New(),
+		Network: "skynet",
+		Address: *ipnet,
+		DNSOn:   true,
+	}
+	if len(network) > 0 {
+		tmpCNode.Network = network
+	}
+	if len(address) > 0 {
+		_, ipnet2, _ := net.ParseCIDR(address)
+		tmpCNode.Address = *ipnet2
+	}
+	createnode := models.Node{
+		CommonNode: tmpCNode,
+	}
 	return &createnode
 }
+
+func createNodeHosts() {
+	k, _ := wgtypes.ParseKey("DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=")
+	linuxHost = models.Host{
+		ID:        uuid.New(),
+		PublicKey: k.PublicKey(),
+		HostPass:  "password",
+		OS:        "linux",
+		Name:      "linuxhost",
+	}
+	_ = logic.CreateHost(&linuxHost)
+	nonLinuxHost = models.Host{
+		ID:        uuid.New(),
+		OS:        "windows",
+		PublicKey: k.PublicKey(),
+		Name:      "windowshost",
+		HostPass:  "password",
+	}
+
+	_ = logic.CreateHost(&nonLinuxHost)
+}

+ 0 - 1
dev.yaml

@@ -32,7 +32,6 @@ server:
   frontendurl: ""
   displaykeys: ""
   azuretenant: ""
-  rce: "off"
   telemetry: ""
   manageiptables: "off"
   portforwardservices: ""

+ 1 - 0
ee/logic/failover.go

@@ -23,6 +23,7 @@ func ResetFailover(network string) error {
 		return err
 	}
 	for _, node := range nodes {
+		node := node
 		err = SetFailover(&node)
 		if err != nil {
 			logger.Log(2, "error setting failover for node", node.ID.String(), ":", err.Error())

+ 2 - 4
go.mod

@@ -20,7 +20,7 @@ require (
 	golang.org/x/oauth2 v0.3.0
 	golang.org/x/sys v0.3.0 // indirect
 	golang.org/x/text v0.5.0 // indirect
-	golang.zx2c4.com/wireguard v0.0.0-20220920152132-bb719d3a6e2c
+	golang.zx2c4.com/wireguard v0.0.0-20220920152132-bb719d3a6e2c // indirect
 	golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220324164955-056925b7df31
 	google.golang.org/protobuf v1.28.1 // indirect
 	gopkg.in/yaml.v3 v3.0.1
@@ -29,7 +29,7 @@ require (
 require (
 	filippo.io/edwards25519 v1.0.0
 	github.com/c-robinson/iplib v1.0.6
-	github.com/go-ping/ping v1.1.0 // indirect
+	github.com/go-ping/ping v1.1.0
 	github.com/posthog/posthog-go v0.0.0-20211028072449-93c17c49e2b0
 )
 
@@ -37,13 +37,11 @@ require (
 	github.com/coreos/go-oidc/v3 v3.5.0
 	github.com/gorilla/websocket v1.5.0
 	github.com/pkg/errors v0.9.1
-	github.com/sirupsen/logrus v1.9.0
 	golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e
 	gortc.io/stun v1.23.0
 )
 
 require (
-	github.com/gravitl/netclient v0.0.0-20230114051017-65ecaeffca09
 	github.com/guumaster/tablewriter v0.0.10
 	github.com/matryer/is v1.4.0
 	github.com/olekukonko/tablewriter v0.0.5

+ 2 - 7
go.sum

@@ -62,8 +62,6 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7
 github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
 github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/gravitl/netclient v0.0.0-20230114051017-65ecaeffca09 h1:T0gLl+i8whnrdwtW91R4u8x8bmqFVfPTU9WfBratkMc=
-github.com/gravitl/netclient v0.0.0-20230114051017-65ecaeffca09/go.mod h1:g3q+vhLySW/6smOsWsVy5LrxoW++f+kqiBAp9BM6sbY=
 github.com/guumaster/tablewriter v0.0.10 h1:A0HD94yMdt4usgxBjoEceNeE0XMJ027euoHAzsPqBQs=
 github.com/guumaster/tablewriter v0.0.10/go.mod h1:p4FRFhyfo0UD9ZLmMRbbJooTUsxo6b80qZTERVDWrH8=
 github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
@@ -76,8 +74,8 @@ github.com/josharian/native v1.0.0 h1:Ts/E8zCSEsG17dUqv7joXJFybuMLjQfWE04tsBODTx
 github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
 github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
-github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -119,16 +117,14 @@ github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
 github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
+github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
 github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
-github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
 github.com/rqlite/gorqlite v0.0.0-20210514125552-08ff1e76b22f h1:BSnJgAfHzEp7o8PYJ7YfwAVHhqu7BYUTggcn/LGlUWY=
 github.com/rqlite/gorqlite v0.0.0-20210514125552-08ff1e76b22f/go.mod h1:UW/gxgQwSePTvL1KA8QEHsXeYHP4xkoXgbDdN781p34=
 github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
-github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
 github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
@@ -208,7 +204,6 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
 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.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
 golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

+ 0 - 5
logic/accesskeys.go

@@ -40,10 +40,6 @@ func CreateAccessKey(accesskey models.AccessKey, network models.Network) (models
 			return models.AccessKey{}, errors.New("duplicate AccessKey Name")
 		}
 	}
-	privAddr := ""
-	if network.IsLocal != "" {
-		privAddr = network.LocalRange
-	}
 
 	netID := network.NetID
 
@@ -52,7 +48,6 @@ func CreateAccessKey(accesskey models.AccessKey, network models.Network) (models
 	accessToken.APIConnString = servercfg.GetAPIConnString()
 	accessToken.ClientConfig.Network = netID
 	accessToken.ClientConfig.Key = accesskey.Value
-	accessToken.ClientConfig.LocalRange = privAddr
 
 	tokenjson, err := json.Marshal(accessToken)
 	if err != nil {

+ 33 - 6
logic/dns.go

@@ -74,14 +74,27 @@ func GetNodeDNS(network string) ([]models.DNSEntry, error) {
 	}
 
 	for _, value := range collection {
-		var entry models.DNSEntry
 		var node models.Node
 		if err = json.Unmarshal([]byte(value), &node); err != nil {
 			continue
 		}
-		if err = json.Unmarshal([]byte(value), &entry); node.Network == network && err == nil {
-			dns = append(dns, entry)
+		if node.Network != network {
+			continue
+		}
+		host, err := GetHost(node.HostID.String())
+		if err != nil {
+			continue
+		}
+		var entry = models.DNSEntry{}
+		entry.Name = host.Name
+		entry.Network = network
+		if node.Address.IP != nil {
+			entry.Address = node.Address.IP.String()
+		}
+		if node.Address6.IP != nil {
+			entry.Address6 = node.Address6.IP.String()
 		}
+		dns = append(dns, entry)
 	}
 
 	return dns, nil
@@ -220,9 +233,6 @@ func ValidateDNSUpdate(change models.DNSEntry, entry models.DNSEntry) error {
 	})
 	_ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
 		_, err := GetParentNetwork(change.Network)
-		if err != nil {
-			logger.Log(0, err.Error())
-		}
 		return err == nil
 	})
 
@@ -245,3 +255,20 @@ func DeleteDNS(domain string, network string) error {
 	err = database.DeleteRecord(database.DNS_TABLE_NAME, key)
 	return err
 }
+
+// CreateDNS - creates a DNS entry
+func CreateDNS(entry models.DNSEntry) (models.DNSEntry, error) {
+
+	k, err := GetRecordKey(entry.Name, entry.Network)
+	if err != nil {
+		return models.DNSEntry{}, err
+	}
+
+	data, err := json.Marshal(&entry)
+	if err != nil {
+		return models.DNSEntry{}, err
+	}
+
+	err = database.Insert(k, string(data), database.DNS_TABLE_NAME)
+	return entry, err
+}

+ 0 - 11
logic/extpeers.go

@@ -138,12 +138,6 @@ func CreateExtClient(extclient *models.ExtClient) error {
 				return err
 			}
 			extclient.Address = newAddress.String()
-
-			extclientInternalAddr, err := UniqueAddress(extclient.Network, false)
-			if err != nil {
-				return err
-			}
-			extclient.InternalIPAddr = extclientInternalAddr.String()
 		}
 	}
 
@@ -154,11 +148,6 @@ func CreateExtClient(extclient *models.ExtClient) error {
 				return err
 			}
 			extclient.Address6 = addr6.String()
-			extclientInternalAddr6, err := UniqueAddress6(extclient.Network, false)
-			if err != nil {
-				return err
-			}
-			extclient.InternalIPAddr6 = extclientInternalAddr6.String()
 		}
 	}
 

+ 3 - 246
logic/gateway.go

@@ -4,7 +4,6 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
-	"strings"
 	"time"
 
 	"github.com/gravitl/netmaker/database"
@@ -48,62 +47,6 @@ func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, erro
 	node.EgressGatewayRanges = gateway.Ranges
 	node.EgressGatewayNatEnabled = models.ParseBool(gateway.NatEnabled)
 	node.EgressGatewayRequest = gateway // store entire request for use when preserving the egress gateway
-	postUpCmd := ""
-	postDownCmd := ""
-	ipv4, ipv6 := getNetworkProtocols(gateway.Ranges)
-	logger.Log(3, "creating egress gateway firewall in use is '", host.FirewallInUse, "'")
-	iface := models.WIREGUARD_INTERFACE
-	if host.OS == "linux" {
-		switch host.FirewallInUse {
-		case models.FIREWALL_NFTABLES:
-			// nftables only supported on Linux
-			// assumes chains eg FORWARD and postrouting already exist
-			logger.Log(3, "creating egress gateway nftables is present")
-			// down commands don't remove as removal of the rules leaves an empty chain while
-			// removing the chain with rules in it would remove all rules in that section (not safe
-			// if there are remaining rules on the host that need to stay).  In practice the chain is removed
-			// when non-empty even though the removal of a non-empty chain should not be possible per nftables wiki.
-			postUpCmd, postDownCmd = firewallNFTCommandsCreateEgress(iface, gateway.Interface, gateway.Ranges, node.EgressGatewayNatEnabled, ipv4, ipv6)
-
-		default: // iptables assumed
-			logger.Log(3, "creating egress gateway nftables is not present")
-			postUpCmd, postDownCmd = firewallIPTablesCommandsCreateEgress(iface, gateway.Interface, node.EgressGatewayNatEnabled, ipv4, ipv6)
-		}
-	}
-	if host.OS == "freebsd" {
-		// spacing around ; is important for later parsing of postup/postdown in wireguard/common.go
-		postUpCmd = "kldload ipfw ipfw_nat ; "
-		postUpCmd += "ipfw disable one_pass ; "
-		postUpCmd += "ipfw nat 1 config if " + gateway.Interface + " same_ports unreg_only reset ; "
-		postUpCmd += "ipfw add 64000 reass all from any to any in ; "
-		postUpCmd += "ipfw add 64000 nat 1 ip from any to any in via " + gateway.Interface + " ; "
-		postUpCmd += "ipfw add 64000 check-state ; "
-		postUpCmd += "ipfw add 64000 nat 1 ip from any to any out via " + gateway.Interface + " ; "
-		postUpCmd += "ipfw add 65534 allow ip from any to any ; "
-		postDownCmd = "ipfw delete 64000 ; "
-		postDownCmd += "ipfw delete 65534 ; "
-		postDownCmd += "kldunload ipfw_nat ipfw"
-
-	}
-	if gateway.PostUp != "" {
-		postUpCmd = gateway.PostUp
-	}
-	if gateway.PostDown != "" {
-		postDownCmd = gateway.PostDown
-	}
-	if node.PostUp != "" {
-		if !strings.Contains(node.PostUp, postUpCmd) {
-			postUpCmd = node.PostUp + postUpCmd
-		}
-	}
-	if node.PostDown != "" {
-		if !strings.Contains(node.PostDown, postDownCmd) {
-			postDownCmd = node.PostDown + postDownCmd
-		}
-	}
-
-	node.PostUp = postUpCmd
-	node.PostDown = postDownCmd
 	node.SetLastModified()
 	nodeData, err := json.Marshal(&node)
 	if err != nil {
@@ -136,39 +79,9 @@ func DeleteEgressGateway(network, nodeid string) (models.Node, error) {
 	if err != nil {
 		return models.Node{}, err
 	}
-	host, err := GetHost(node.HostID.String())
-	if err != nil {
-		return models.Node{}, err
-
-	}
 	node.IsEgressGateway = false
 	node.EgressGatewayRanges = []string{}
 	node.EgressGatewayRequest = models.EgressGatewayRequest{} // remove preserved request as the egress gateway is gone
-	// needed in case we don't preserve a gateway (i.e., no ingress to preserve)
-	node.PostUp = ""
-	node.PostDown = ""
-	cidrs := []string{}
-	cidrs = append(cidrs, node.IngressGatewayRange)
-	cidrs = append(cidrs, node.IngressGatewayRange6)
-	ipv4, ipv6 := getNetworkProtocols(cidrs)
-	logger.Log(3, "deleting egress gateway firewall in use is '", host.FirewallInUse, "'")
-	if node.IsIngressGateway { // check if node is still an ingress gateway before completely deleting postdown/up rules
-		// still have an ingress gateway so preserve it
-		iface := models.WIREGUARD_INTERFACE
-		if host.OS == "linux" {
-			switch host.FirewallInUse {
-			case models.FIREWALL_NFTABLES:
-				// nftables only supported on Linux
-				// assumes chains eg FORWARD and postrouting already exist
-				logger.Log(3, "deleting egress gateway nftables is present")
-				node.PostUp, node.PostDown = firewallNFTCommandsCreateIngress(iface)
-			default:
-				logger.Log(3, "deleting egress gateway nftables is not present")
-				node.PostUp, node.PostDown = firewallIPTablesCommandsCreateIngress(iface, ipv4, ipv6)
-			}
-		}
-		// no need to preserve ingress gateway on FreeBSD as ingress is not supported on that OS
-	}
 	node.SetLastModified()
 
 	data, err := json.Marshal(&node)
@@ -184,7 +97,6 @@ func DeleteEgressGateway(network, nodeid string) (models.Node, error) {
 // CreateIngressGateway - creates an ingress gateway
 func CreateIngressGateway(netid string, nodeid string, failover bool) (models.Node, error) {
 
-	var postUpCmd, postDownCmd string
 	node, err := GetNodeByID(nodeid)
 	if err != nil {
 		return models.Node{}, err
@@ -193,6 +105,9 @@ func CreateIngressGateway(netid string, nodeid string, failover bool) (models.No
 	if err != nil {
 		return models.Node{}, err
 	}
+	if host.OS != "linux" {
+		return models.Node{}, errors.New("ingress can only be created on linux based node")
+	}
 	if host.FirewallInUse == models.FIREWALL_NONE {
 		return models.Node{}, errors.New("firewall is not supported for ingress gateways")
 	}
@@ -202,38 +117,9 @@ func CreateIngressGateway(netid string, nodeid string, failover bool) (models.No
 		return models.Node{}, err
 	}
 	node.IsIngressGateway = true
-	cidrs := []string{}
-	cidrs = append(cidrs, network.AddressRange)
-	cidrs = append(cidrs, network.AddressRange6)
 	node.IngressGatewayRange = network.AddressRange
 	node.IngressGatewayRange6 = network.AddressRange6
-	ipv4, ipv6 := getNetworkProtocols(cidrs)
-	logger.Log(3, "creating ingress gateway firewall in use is '", host.FirewallInUse, "'")
-	iface := models.WIREGUARD_INTERFACE
-	switch host.FirewallInUse {
-	case models.FIREWALL_NFTABLES:
-		// nftables only supported on Linux
-		// assumes chains eg FORWARD and postrouting already exist
-		logger.Log(3, "creating ingress gateway nftables is present")
-		postUpCmd, postDownCmd = firewallNFTCommandsCreateIngress(iface)
-	default:
-		logger.Log(3, "creating ingress gateway using nftables is not present")
-		postUpCmd, postDownCmd = firewallIPTablesCommandsCreateIngress(iface, ipv4, ipv6)
-	}
-
-	if node.PostUp != "" {
-		if !strings.Contains(node.PostUp, postUpCmd) {
-			postUpCmd = node.PostUp + postUpCmd
-		}
-	}
-	if node.PostDown != "" {
-		if !strings.Contains(node.PostDown, postDownCmd) {
-			postDownCmd = node.PostDown + postDownCmd
-		}
-	}
 	node.SetLastModified()
-	node.PostUp = postUpCmd
-	node.PostDown = postDownCmd
 	if failover && servercfg.Is_EE {
 		node.Failover = true
 	}
@@ -274,10 +160,6 @@ func DeleteIngressGateway(networkName string, nodeid string) (models.Node, bool,
 	node.IngressGatewayRange = ""
 	node.Failover = false
 
-	// default to removing postup and postdown
-	node.PostUp = ""
-	node.PostDown = ""
-
 	//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)
@@ -315,128 +197,3 @@ func DeleteGatewayExtClients(gatewayID string, networkName string) error {
 	}
 	return nil
 }
-
-// firewallNFTCommandsCreateIngress - used to centralize firewall command maintenance for creating an ingress gateway using the nftables firewall.
-func firewallNFTCommandsCreateIngress(networkInterface string) (string, string) {
-	// spacing around ; is important for later parsing of postup/postdown in wireguard/common.go
-	postUp := "nft add table ip filter ; "
-	postUp += "nft add chain ip filter FORWARD ; "
-	postUp += "nft add rule ip filter FORWARD iifname " + networkInterface + " counter accept ; "
-	postUp += "nft add rule ip filter FORWARD oifname " + networkInterface + " counter accept ; "
-	postUp += "nft add table nat ; "
-	postUp += "nft add chain nat postrouting ; "
-	postUp += "nft add rule ip nat postrouting oifname " + networkInterface + " counter masquerade ; "
-
-	// doesn't remove potentially empty tables or chains
-	postDown := "nft flush table filter ; "
-	postDown += "nft flush table nat ; "
-
-	return postUp, postDown
-}
-
-// firewallNFTCommandsCreateEgress - used to centralize firewall command maintenance for creating an egress gateway using the nftables firewall.
-func firewallNFTCommandsCreateEgress(networkInterface string, gatewayInterface string, gatewayranges []string, egressNatEnabled bool, ipv4, ipv6 bool) (string, string) {
-	// spacing around ; is important for later parsing of postup/postdown in wireguard/common.go
-	postUp := ""
-	postDown := ""
-	if ipv4 {
-		postUp += "nft add table ip filter ; "
-		postUp += "nft add chain ip filter forward ; "
-		postUp += "nft add rule filter forward ct state related,established accept ; "
-		postUp += "nft add rule ip filter forward iifname " + networkInterface + " accept ; "
-		postUp += "nft add rule ip filter forward oifname " + networkInterface + " accept ; "
-		postUp += "nft add table nat ; "
-		postUp += "nft 'add chain ip nat prerouting { type nat hook prerouting priority 0 ;}' ; "
-		postUp += "nft 'add chain ip nat postrouting { type nat hook postrouting priority 0 ;}' ; "
-
-		postDown += "nft flush table filter ; "
-
-		if egressNatEnabled {
-			postUp += "nft add table nat ; "
-			postUp += "nft add chain nat postrouting ; "
-			postUp += "nft add rule ip nat postrouting oifname " + gatewayInterface + " counter masquerade ; "
-
-			postDown += "nft flush table nat ; "
-		}
-	}
-	if ipv6 {
-		postUp += "nft add table ip6 filter ; "
-		postUp += "nft add chain ip6 filter forward ; "
-		postUp += "nft add rule ip6 filter forward ct state related,established accept ; "
-		postUp += "nft add rule ip6 filter forward iifname " + networkInterface + " accept ; "
-		postUp += "nft add rule ip6 filter forward oifname " + networkInterface + " accept ; "
-
-		postDown += "nft flush table ip6 filter ; "
-
-		if egressNatEnabled {
-			postUp += "nft add table ip6 nat ; "
-			postUp += "nft 'add chain ip6 nat prerouting { type nat hook prerouting priority 0 ;}' ; "
-			postUp += "nft 'add chain ip6 nat postrouting { type nat hook postrouting priority 0 ;}' ; "
-			postUp += "nft add rule ip6 nat postrouting oifname " + gatewayInterface + " masquerade ; "
-
-			postDown += "nft flush table ip6 nat ; "
-		}
-	}
-
-	return postUp, postDown
-}
-
-// firewallIPTablesCommandsCreateIngress - used to centralize firewall command maintenance for creating an ingress gateway using the iptables firewall.
-func firewallIPTablesCommandsCreateIngress(networkInterface string, ipv4, ipv6 bool) (string, string) {
-	postUp := ""
-	postDown := ""
-	if ipv4 {
-		// spacing around ; is important for later parsing of postup/postdown in wireguard/common.go
-		postUp += "iptables -A FORWARD -i " + networkInterface + " -j ACCEPT ; "
-		postUp += "iptables -A FORWARD -o " + networkInterface + " -j ACCEPT ; "
-		postUp += "iptables -t nat -A POSTROUTING -o " + networkInterface + " -j MASQUERADE ; "
-
-		// doesn't remove potentially empty tables or chains
-		postDown += "iptables -D FORWARD -i " + networkInterface + " -j ACCEPT ; "
-		postDown += "iptables -D FORWARD -o " + networkInterface + " -j ACCEPT ; "
-		postDown += "iptables -t nat -D POSTROUTING -o " + networkInterface + " -j MASQUERADE ; "
-	}
-	if ipv6 {
-		// spacing around ; is important for later parsing of postup/postdown in wireguard/common.go
-		postUp += "ip6tables -A FORWARD -i " + networkInterface + " -j ACCEPT ; "
-		postUp += "ip6tables -A FORWARD -o " + networkInterface + " -j ACCEPT ; "
-		postUp += "ip6tables -t nat -A POSTROUTING -o " + networkInterface + " -j MASQUERADE ; "
-
-		// doesn't remove potentially empty tables or chains
-		postDown += "ip6tables -D FORWARD -i " + networkInterface + " -j ACCEPT ; "
-		postDown += "ip6tables -D FORWARD -o " + networkInterface + " -j ACCEPT ; "
-		postDown += "ip6tables -t nat -D POSTROUTING -o " + networkInterface + " -j MASQUERADE ; "
-	}
-	return postUp, postDown
-}
-
-// firewallIPTablesCommandsCreateEgress - used to centralize firewall command maintenance for creating an egress gateway using the iptables firewall.
-func firewallIPTablesCommandsCreateEgress(networkInterface string, gatewayInterface string, egressNatEnabled bool, ipv4, ipv6 bool) (string, string) {
-	// spacing around ; is important for later parsing of postup/postdown in wireguard/common.go
-	postUp := ""
-	postDown := ""
-	if ipv4 {
-		postUp += "iptables -A FORWARD -i " + networkInterface + " -j ACCEPT ; "
-		postUp += "iptables -A FORWARD -o " + networkInterface + " -j ACCEPT ; "
-		postDown += "iptables -D FORWARD -i " + networkInterface + " -j ACCEPT ; "
-		postDown += "iptables -D FORWARD -o " + networkInterface + " -j ACCEPT ; "
-
-		if egressNatEnabled {
-			postUp += "iptables -t nat -A POSTROUTING -o " + gatewayInterface + " -j MASQUERADE ; "
-			postDown += "iptables -t nat -D POSTROUTING -o " + gatewayInterface + " -j MASQUERADE ; "
-		}
-	}
-	if ipv6 {
-		postUp += "ip6tables -A FORWARD -i " + networkInterface + " -j ACCEPT ; "
-		postUp += "ip6tables -A FORWARD -o " + networkInterface + " -j ACCEPT ; "
-		postDown += "ip6tables -D FORWARD -i " + networkInterface + " -j ACCEPT ; "
-		postDown += "ip6tables -D FORWARD -o " + networkInterface + " -j ACCEPT ; "
-
-		if egressNatEnabled {
-			postUp += "ip6tables -t nat -A POSTROUTING -o " + gatewayInterface + " -j MASQUERADE ; "
-			postDown += "ip6tables -t nat -D POSTROUTING -o " + gatewayInterface + " -j MASQUERADE ; "
-		}
-	}
-	return postUp, postDown
-
-}

+ 62 - 0
logic/host_test.go

@@ -0,0 +1,62 @@
+package logic
+
+import (
+	"net"
+	"testing"
+
+	"github.com/google/uuid"
+	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/models"
+	"github.com/matryer/is"
+)
+
+func TestCheckPorts(t *testing.T) {
+	database.InitializeDatabase()
+	h := models.Host{
+		ID:              uuid.New(),
+		EndpointIP:      net.ParseIP("192.168.1.1"),
+		ListenPort:      51821,
+		ProxyListenPort: maxPort,
+	}
+	testHost := models.Host{
+		ID:              uuid.New(),
+		EndpointIP:      net.ParseIP("192.168.1.1"),
+		ListenPort:      51830,
+		ProxyListenPort: 51730,
+	}
+	CreateHost(&h)
+	t.Run("no change", func(t *testing.T) {
+		is := is.New(t)
+		CheckHostPorts(&testHost)
+		is.Equal(testHost.ListenPort, 51830)
+		is.Equal(testHost.ProxyListenPort, 51730)
+	})
+	t.Run("same listen port", func(t *testing.T) {
+		is := is.New(t)
+		testHost.ListenPort = 51821
+		CheckHostPorts(&testHost)
+		is.Equal(testHost.ListenPort, 51822)
+		is.Equal(testHost.ProxyListenPort, 51730)
+	})
+	t.Run("same proxy port", func(t *testing.T) {
+		is := is.New(t)
+		testHost.ProxyListenPort = 65535
+		CheckHostPorts(&testHost)
+		is.Equal(testHost.ListenPort, 51822)
+		is.Equal(testHost.ProxyListenPort, minPort)
+	})
+	t.Run("listenport equals proxy port", func(t *testing.T) {
+		is := is.New(t)
+		testHost.ListenPort = maxPort
+		CheckHostPorts(&testHost)
+		is.Equal(testHost.ListenPort, minPort)
+		is.Equal(testHost.ProxyListenPort, minPort+1)
+	})
+	t.Run("proxyport equals listenport", func(t *testing.T) {
+		is := is.New(t)
+		testHost.ProxyListenPort = 51821
+		CheckHostPorts(&testHost)
+		is.Equal(testHost.ListenPort, minPort)
+		is.Equal(testHost.ProxyListenPort, 51822)
+	})
+}

+ 85 - 4
logic/hosts.go

@@ -20,6 +20,11 @@ var (
 	ErrInvalidHostID error = errors.New("invalid host id")
 )
 
+const (
+	maxPort = 1<<16 - 1
+	minPort = 1025
+)
+
 // GetAllHosts - returns all hosts in flat list or error
 func GetAllHosts() ([]models.Host, error) {
 	currHostMap, err := GetHostsMap()
@@ -117,10 +122,6 @@ func UpdateHost(newHost, currentHost *models.Host) {
 		newHost.Name = currentHost.Name
 	}
 
-	if newHost.LocalRange.String() != currentHost.LocalRange.String() {
-		newHost.LocalRange = currentHost.LocalRange
-	}
-
 	if newHost.MTU == 0 {
 		newHost.MTU = currentHost.MTU
 	}
@@ -132,6 +133,42 @@ func UpdateHost(newHost, currentHost *models.Host) {
 	if newHost.ProxyListenPort == 0 {
 		newHost.ProxyListenPort = currentHost.ProxyListenPort
 	}
+	newHost.PublicListenPort = currentHost.PublicListenPort
+
+}
+
+// UpdateHostFromClient - used for updating host on server with update recieved from client
+func UpdateHostFromClient(newHost, currHost *models.Host) (sendPeerUpdate bool) {
+
+	if newHost.ListenPort != 0 && currHost.ListenPort != newHost.ListenPort {
+		currHost.ListenPort = newHost.ListenPort
+		sendPeerUpdate = true
+	}
+	if newHost.ProxyListenPort != 0 && currHost.ProxyListenPort != newHost.ProxyListenPort {
+		currHost.ProxyListenPort = newHost.ProxyListenPort
+		sendPeerUpdate = true
+	}
+	if newHost.PublicListenPort != 0 && currHost.PublicListenPort != newHost.PublicListenPort {
+		currHost.PublicListenPort = newHost.PublicListenPort
+		sendPeerUpdate = true
+	}
+	if currHost.ProxyEnabled != newHost.ProxyEnabled {
+		currHost.ProxyEnabled = newHost.ProxyEnabled
+		sendPeerUpdate = true
+	}
+	if currHost.EndpointIP.String() != newHost.EndpointIP.String() {
+		currHost.EndpointIP = newHost.EndpointIP
+		sendPeerUpdate = true
+	}
+	currHost.DaemonInstalled = newHost.DaemonInstalled
+	currHost.Debug = newHost.Debug
+	currHost.Verbosity = newHost.Verbosity
+	currHost.Version = newHost.Version
+	if newHost.Name != "" {
+		currHost.Name = newHost.Name
+	}
+
+	return
 }
 
 // UpsertHost - upserts into DB a given host model, does not check for existence*
@@ -328,3 +365,47 @@ func GetRelatedHosts(hostID string) []models.Host {
 	}
 	return relatedHosts
 }
+
+// CheckHostPort checks host endpoints to ensures that hosts on the same server
+// with the same endpoint have different listen ports
+// in the case of 64535 hosts or more with same endpoint, ports will not be changed
+func CheckHostPorts(h *models.Host) {
+	portsInUse := make(map[int]bool)
+	hosts, err := GetAllHosts()
+	if err != nil {
+		return
+	}
+	for _, host := range hosts {
+		if host.ID == h.ID {
+			//skip self
+			continue
+		}
+		if !host.EndpointIP.Equal(h.EndpointIP) {
+			continue
+		}
+		portsInUse[host.ListenPort] = true
+		portsInUse[host.ProxyListenPort] = true
+	}
+	// iterate until port is not found or max iteration is reached
+	for i := 0; portsInUse[h.ListenPort] && i < maxPort-minPort+1; i++ {
+		updatePort(&h.ListenPort)
+	}
+	// allocate h.ListenPort so it is unavailable to h.ProxyListenPort
+	portsInUse[h.ListenPort] = true
+	for i := 0; portsInUse[h.ProxyListenPort] && i < maxPort-minPort+1; i++ {
+		updatePort(&h.ProxyListenPort)
+	}
+}
+
+// HostExists - checks if given host already exists
+func HostExists(h *models.Host) bool {
+	_, err := GetHost(h.ID.String())
+	return (err != nil && !database.IsEmptyRecord(err)) || (err == nil)
+}
+
+func updatePort(p *int) {
+	*p++
+	if *p > maxPort {
+		*p = minPort
+	}
+}

+ 1 - 1
logic/jwts.go

@@ -130,7 +130,7 @@ func VerifyUserToken(tokenString string) (username string, networks []string, is
 }
 
 // VerifyToken - [nodes] Only
-func VerifyToken(tokenString string) (nodeID string, mac string, network string, err error) {
+func VerifyToken(tokenString string) (hostID string, mac string, network string, err error) {
 	claims := &models.Claims{}
 
 	// this may be a stupid way of serving up a master key

+ 1 - 1
logic/metrics/metrics.go

@@ -3,9 +3,9 @@ package metrics
 import (
 	"time"
 
-	proxy_metrics "github.com/gravitl/netclient/nmproxy/metrics"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic"
+	proxy_metrics "github.com/gravitl/netmaker/metrics"
 	"github.com/gravitl/netmaker/models"
 	"golang.zx2c4.com/wireguard/wgctrl"
 )

+ 7 - 62
logic/networks.go

@@ -237,12 +237,12 @@ func IsIPUnique(network string, ip string, tableName string, isIpv6 bool) bool {
 				continue
 			}
 			if isIpv6 {
-				if (extClient.Address6 == ip || extClient.InternalIPAddr6 == ip) && extClient.Network == network {
+				if (extClient.Address6 == ip) && extClient.Network == network {
 					return false
 				}
 
 			} else {
-				if (extClient.Address == ip || extClient.InternalIPAddr == ip) && extClient.Network == network {
+				if (extClient.Address == ip) && extClient.Network == network {
 					return false
 				}
 			}
@@ -298,60 +298,6 @@ func UniqueAddress6(networkName string, reverse bool) (net.IP, error) {
 	return add, errors.New("ERROR: No unique IPv6 addresses available. Check network subnet")
 }
 
-// GetLocalIP - gets the local ip
-func GetLocalIP(node models.Node) string {
-	var local string
-	ifaces, err := net.Interfaces()
-	if err != nil {
-		return local
-	}
-	host, err := GetHost(node.HostID.String())
-	if err != nil {
-		return local
-	}
-	localrange := host.LocalRange
-	found := false
-	for _, i := range ifaces {
-		if i.Flags&net.FlagUp == 0 {
-			continue // interface down
-		}
-		if i.Flags&net.FlagLoopback != 0 {
-			continue // loopback interface
-		}
-		addrs, err := i.Addrs()
-		if err != nil {
-			return local
-		}
-		for _, addr := range addrs {
-			var ip net.IP
-			switch v := addr.(type) {
-			case *net.IPNet:
-				if !found {
-					ip = v.IP
-					local = ip.String()
-					if node.IsLocal {
-						found = localrange.Contains(ip)
-					} else {
-						found = true
-					}
-				}
-			case *net.IPAddr:
-				if !found {
-					ip = v.IP
-					local = ip.String()
-					if node.IsLocal {
-						found = localrange.Contains(ip)
-
-					} else {
-						found = true
-					}
-				}
-			}
-		}
-	}
-	return local
-}
-
 // UpdateNetworkLocalAddresses - updates network localaddresses
 func UpdateNetworkLocalAddresses(networkName string) error {
 
@@ -517,14 +463,13 @@ func IsNetworkNameUnique(network *models.Network) (bool, error) {
 }
 
 // UpdateNetwork - updates a network with another network's fields
-func UpdateNetwork(currentNetwork *models.Network, newNetwork *models.Network) (bool, bool, bool, bool, []string, []string, error) {
+func UpdateNetwork(currentNetwork *models.Network, newNetwork *models.Network) (bool, bool, bool, []string, []string, error) {
 	if err := ValidateNetwork(newNetwork, true); err != nil {
-		return false, false, false, false, nil, nil, err
+		return false, false, false, nil, nil, err
 	}
 	if newNetwork.NetID == currentNetwork.NetID {
 		hasrangeupdate4 := newNetwork.AddressRange != currentNetwork.AddressRange
 		hasrangeupdate6 := newNetwork.AddressRange6 != currentNetwork.AddressRange6
-		localrangeupdate := newNetwork.LocalRange != currentNetwork.LocalRange
 		hasholepunchupdate := newNetwork.DefaultUDPHolePunch != currentNetwork.DefaultUDPHolePunch
 		groupDelta := append(StringDifference(newNetwork.ProSettings.AllowedGroups, currentNetwork.ProSettings.AllowedGroups),
 			StringDifference(currentNetwork.ProSettings.AllowedGroups, newNetwork.ProSettings.AllowedGroups)...)
@@ -532,14 +477,14 @@ func UpdateNetwork(currentNetwork *models.Network, newNetwork *models.Network) (
 			StringDifference(currentNetwork.ProSettings.AllowedUsers, newNetwork.ProSettings.AllowedUsers)...)
 		data, err := json.Marshal(newNetwork)
 		if err != nil {
-			return false, false, false, false, nil, nil, err
+			return false, false, false, nil, nil, err
 		}
 		newNetwork.SetNetworkLastModified()
 		err = database.Insert(newNetwork.NetID, string(data), database.NETWORKS_TABLE_NAME)
-		return hasrangeupdate4, hasrangeupdate6, localrangeupdate, hasholepunchupdate, groupDelta, userDelta, err
+		return hasrangeupdate4, hasrangeupdate6, hasholepunchupdate, groupDelta, userDelta, err
 	}
 	// copy values
-	return false, false, false, false, nil, nil, errors.New("failed to update network " + newNetwork.NetID + ", cannot change netid.")
+	return false, false, false, nil, nil, errors.New("failed to update network " + newNetwork.NetID + ", cannot change netid.")
 }
 
 // GetNetwork - gets a network from database

+ 6 - 70
logic/nodes.go

@@ -50,7 +50,7 @@ func GetNetworkNodes(network string) ([]models.Node, error) {
 func UpdateNode(currentNode *models.Node, newNode *models.Node) error {
 	if newNode.Address.IP.String() != currentNode.Address.IP.String() {
 		if network, err := GetParentNetwork(newNode.Network); err == nil {
-			if !IsAddressInCIDR(newNode.Address.IP.String(), network.AddressRange) {
+			if !IsAddressInCIDR(newNode.Address.IP, network.AddressRange) {
 				return fmt.Errorf("invalid address provided; out of network range for node %s", newNode.ID)
 			}
 		}
@@ -203,7 +203,7 @@ func GetAllNodes() ([]models.Node, error) {
 		var node models.Node
 		// ignore legacy nodes in database
 		if err := json.Unmarshal([]byte(value), &node); err != nil {
-			logger.Log(1, "legacy node detected: ", err.Error())
+			logger.Log(3, "legacy node detected: ", err.Error())
 			continue
 		}
 		// add node to our array
@@ -239,7 +239,6 @@ func SetNodeDefaults(node *models.Node) {
 	if err == nil {
 		node.NetworkRange6 = *cidr
 	}
-	node.ExpirationDateTime = time.Now().Add(models.TEN_YEARS_IN_SECONDS)
 
 	if node.DefaultACL == "" {
 		node.DefaultACL = parentNetwork.DefaultACL
@@ -248,49 +247,10 @@ func SetNodeDefaults(node *models.Node) {
 	if node.PersistentKeepalive == 0 {
 		node.PersistentKeepalive = time.Second * time.Duration(parentNetwork.DefaultKeepalive)
 	}
-	if node.PostUp == "" {
-		postup := parentNetwork.DefaultPostUp
-		node.PostUp = postup
-	}
-	if node.PostDown == "" {
-		postdown := parentNetwork.DefaultPostDown
-		node.PostDown = postdown
-	}
-	// == Parent Network settings ==
-
-	// == node defaults if not set by parent ==
-	///TODO ___ REVISIT ------
-	///TODO ___ REVISIT ------
-	///TODO ___ REVISIT ------
-	///TODO ___ REVISIT ------
-	///TODO ___ REVISIT ------
-	//node.SetIPForwardingDefault()
-	//node.SetDNSOnDefault()
-	//node.SetIsLocalDefault()
-	//node.SetLastModified()
-	//node.SetDefaultName()
-	//node.SetLastCheckIn()
-	//node.SetLastPeerUpdate()
-	//node.SetDefaultAction()
-	//node.SetIsServerDefault()
-	//node.SetIsStaticDefault()
-	//node.SetDefaultEgressGateway()
-	//node.SetDefaultIngressGateway()
-	//node.SetDefaulIsPending()
-	//node.SetDefaultMTU()
-	//node.SetDefaultNFTablesPresent()
-	//node.SetDefaultIsRelayed()
-	//node.SetDefaultIsRelay()
-	//node.SetDefaultIsDocker()
-	//node.SetDefaultIsK8S()
-	//node.SetDefaultIsHub()
-	//node.SetDefaultConnected()
-	//node.SetDefaultACL()
-	//node.SetDefaultFailover()
-	///TODO ___ REVISIT ------
-	///TODO ___ REVISIT ------
-	///TODO ___ REVISIT ------
-	///TODO ___ REVISIT ------
+	node.SetLastModified()
+	node.SetLastCheckIn()
+	node.SetDefaultConnected()
+	node.SetExpirationDateTime()
 }
 
 // GetRecordKey - get record key
@@ -302,30 +262,6 @@ func GetRecordKey(id string, network string) (string, error) {
 	return id + "###" + network, nil
 }
 
-// GetNodeByMacAddress - gets a node by mac address
-func GetNodeByMacAddress(network string, macaddress string) (models.Node, error) {
-
-	var node models.Node
-
-	key, err := GetRecordKey(macaddress, network)
-	if err != nil {
-		return node, err
-	}
-
-	record, err := database.FetchRecord(database.NODES_TABLE_NAME, key)
-	if err != nil {
-		return models.Node{}, err
-	}
-
-	if err = json.Unmarshal([]byte(record), &node); err != nil {
-		return models.Node{}, err
-	}
-
-	SetNodeDefaults(&node)
-
-	return node, nil
-}
-
 // GetNodesByAddress - gets a node by mac address
 func GetNodesByAddress(network string, addresses []string) ([]models.Node, error) {
 	var nodes []models.Node

+ 99 - 76
logic/peers.go

@@ -5,12 +5,12 @@ import (
 	"fmt"
 	"log"
 	"net"
+	"net/netip"
 	"sort"
 	"strconv"
 	"strings"
 	"time"
 
-	proxy_models "github.com/gravitl/netclient/nmproxy/models"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic/acls/nodeacls"
@@ -28,10 +28,10 @@ import (
 // TODO ==========================
 // TODO ==========================
 // revisit this logic with new host/node models.
-func GetPeersForProxy(node *models.Node, onlyPeers bool) (proxy_models.ProxyManagerPayload, error) {
-	proxyPayload := proxy_models.ProxyManagerPayload{}
+func GetPeersForProxy(node *models.Node, onlyPeers bool) (models.ProxyManagerPayload, error) {
+	proxyPayload := models.ProxyManagerPayload{}
 	var peers []wgtypes.PeerConfig
-	peerConfMap := make(map[string]proxy_models.PeerConf)
+	peerConfMap := make(map[string]models.PeerConf)
 	var err error
 	currentPeers, err := GetNetworkNodes(node.Network)
 	if err != nil {
@@ -70,8 +70,9 @@ func GetPeersForProxy(node *models.Node, onlyPeers bool) (proxy_models.ProxyMana
 				logger.Log(1, "failed to relayed nodes: ", node.ID.String(), err.Error())
 				proxyPayload.IsRelay = false
 			} else {
-				relayPeersMap := make(map[string]proxy_models.RelayedConf)
+				relayPeersMap := make(map[string]models.RelayedConf)
 				for _, relayedNode := range relayedNodes {
+					relayedNode := relayedNode
 					payload, err := GetPeersForProxy(&relayedNode, true)
 					if err == nil {
 						relayedHost, err := GetHost(relayedNode.HostID.String())
@@ -80,7 +81,7 @@ func GetPeersForProxy(node *models.Node, onlyPeers bool) (proxy_models.ProxyMana
 						}
 						relayedEndpoint, udpErr := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", relayedHost.EndpointIP, host.ListenPort))
 						if udpErr == nil {
-							relayPeersMap[host.PublicKey.String()] = proxy_models.RelayedConf{
+							relayPeersMap[host.PublicKey.String()] = models.RelayedConf{
 								RelayedPeerEndpoint: relayedEndpoint,
 								RelayedPeerPubKey:   relayedHost.PublicKey.String(),
 								Peers:               payload.Peers,
@@ -110,7 +111,7 @@ func GetPeersForProxy(node *models.Node, onlyPeers bool) (proxy_models.ProxyMana
 		if proxyStatus {
 			listenPort = host.ProxyListenPort
 			if listenPort == 0 {
-				listenPort = proxy_models.NmProxyPort
+				listenPort = models.NmProxyPort
 			}
 		} else if listenPort == 0 {
 			listenPort = host.ListenPort
@@ -135,7 +136,7 @@ func GetPeersForProxy(node *models.Node, onlyPeers bool) (proxy_models.ProxyMana
 			PersistentKeepaliveInterval: &keepalive,
 			ReplaceAllowedIPs:           true,
 		})
-		peerConfMap[host.PublicKey.String()] = proxy_models.PeerConf{
+		peerConfMap[host.PublicKey.String()] = models.PeerConf{
 			Address:          net.ParseIP(peer.PrimaryAddress()),
 			Proxy:            proxyStatus,
 			PublicListenPort: int32(listenPort),
@@ -151,7 +152,7 @@ func GetPeersForProxy(node *models.Node, onlyPeers bool) (proxy_models.ProxyMana
 				}
 				relayTo, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", relayHost.EndpointIP, relayHost.ListenPort))
 				if err == nil {
-					peerConfMap[host.PublicKey.String()] = proxy_models.PeerConf{
+					peerConfMap[host.PublicKey.String()] = models.PeerConf{
 
 						IsRelayed:        true,
 						RelayedTo:        relayTo,
@@ -192,11 +193,11 @@ func GetPeersForProxy(node *models.Node, onlyPeers bool) (proxy_models.ProxyMana
 }
 
 // GetProxyUpdateForHost - gets the proxy update for host
-func GetProxyUpdateForHost(host *models.Host) (proxy_models.ProxyManagerPayload, error) {
-	proxyPayload := proxy_models.ProxyManagerPayload{
-		Action: proxy_models.ProxyUpdate,
+func GetProxyUpdateForHost(host *models.Host) (models.ProxyManagerPayload, error) {
+	proxyPayload := models.ProxyManagerPayload{
+		Action: models.ProxyUpdate,
 	}
-	peerConfMap := make(map[string]proxy_models.PeerConf)
+	peerConfMap := make(map[string]models.PeerConf)
 	if host.IsRelayed {
 		relayHost, err := GetHost(host.RelayedBy)
 		if err == nil {
@@ -213,13 +214,14 @@ func GetProxyUpdateForHost(host *models.Host) (proxy_models.ProxyManagerPayload,
 	}
 	if host.IsRelay {
 		relayedHosts := GetRelayedHosts(host)
-		relayPeersMap := make(map[string]proxy_models.RelayedConf)
+		relayPeersMap := make(map[string]models.RelayedConf)
 		for _, relayedHost := range relayedHosts {
+			relayedHost := relayedHost
 			payload, err := GetPeerUpdateForHost(&relayedHost)
 			if err == nil {
 				relayedEndpoint, udpErr := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", relayedHost.EndpointIP, getPeerListenPort(&relayedHost)))
 				if udpErr == nil {
-					relayPeersMap[relayedHost.PublicKey.String()] = proxy_models.RelayedConf{
+					relayPeersMap[relayedHost.PublicKey.String()] = models.RelayedConf{
 						RelayedPeerEndpoint: relayedEndpoint,
 						RelayedPeerPubKey:   relayedHost.PublicKey.String(),
 						Peers:               payload.Peers,
@@ -252,11 +254,10 @@ func GetProxyUpdateForHost(host *models.Host) (proxy_models.ProxyManagerPayload,
 			if err != nil {
 				continue
 			}
-
-			var currPeerConf proxy_models.PeerConf
+			var currPeerConf models.PeerConf
 			var found bool
 			if currPeerConf, found = peerConfMap[peerHost.PublicKey.String()]; !found {
-				currPeerConf = proxy_models.PeerConf{
+				currPeerConf = models.PeerConf{
 					Proxy:            peerHost.ProxyEnabled,
 					PublicListenPort: int32(getPeerListenPort(peerHost)),
 				}
@@ -299,12 +300,16 @@ func GetPeerUpdateForHost(host *models.Host) (models.HostPeerUpdate, error) {
 	}
 	hostPeerUpdate := models.HostPeerUpdate{
 		Host:          *host,
+		Server:        servercfg.GetServer(),
 		Network:       make(map[string]models.NetworkInfo),
 		PeerIDs:       make(models.HostPeerMap),
 		ServerVersion: servercfg.GetVersion(),
 		ServerAddrs:   []models.ServerAddr{},
+		IngressInfo: models.IngressInfo{
+			ExtPeers: make(map[string]models.ExtClientInfo),
+		},
 	}
-	log.Println("peer update for host ", host.ID.String())
+	logger.Log(1, "peer update for host ", host.ID.String())
 	peerIndexMap := make(map[string]int)
 	for _, nodeID := range host.Nodes {
 		node, err := GetNodeByID(nodeID)
@@ -314,6 +319,7 @@ func GetPeerUpdateForHost(host *models.Host) (models.HostPeerUpdate, error) {
 		if !node.Connected || node.Action == models.NODE_DELETE || node.PendingDelete {
 			continue
 		}
+
 		hostPeerUpdate.Network[node.Network] = models.NetworkInfo{
 			DNS: getPeerDNS(node.Network),
 		}
@@ -322,9 +328,13 @@ func GetPeerUpdateForHost(host *models.Host) (models.HostPeerUpdate, error) {
 			log.Println("no network nodes")
 			return models.HostPeerUpdate{}, err
 		}
+		var extClientPeerMap map[string]models.PeerExtInfo
+		if node.IsIngressGateway {
+			extClientPeerMap = make(map[string]models.PeerExtInfo)
+		}
 		for _, peer := range currentPeers {
 			if peer.ID == node.ID {
-				log.Println("peer update, skipping self")
+				logger.Log(2, "peer update, skipping self")
 				//skip yourself
 
 				continue
@@ -332,12 +342,12 @@ func GetPeerUpdateForHost(host *models.Host) (models.HostPeerUpdate, error) {
 			var peerConfig wgtypes.PeerConfig
 			peerHost, err := GetHost(peer.HostID.String())
 			if err != nil {
-				log.Println("no peer host", err)
+				logger.Log(1, "no peer host", peer.HostID.String(), err.Error())
 				return models.HostPeerUpdate{}, err
 			}
 
-			if !peer.Connected {
-				log.Println("peer update, skipping unconnected node")
+			if !peer.Connected || peer.Action == models.NODE_DELETE || peer.PendingDelete {
+				logger.Log(2, "peer update, skipping unconnected node", peer.ID.String())
 				//skip unconnected nodes
 				continue
 			}
@@ -383,6 +393,17 @@ func GetPeerUpdateForHost(host *models.Host) (models.HostPeerUpdate, error) {
 				allowedips = append(allowedips, getEgressIPs(&node, &peer)...)
 			}
 			peerConfig.AllowedIPs = allowedips
+			if node.IsIngressGateway {
+
+				extClientPeerMap[peerHost.PublicKey.String()] = models.PeerExtInfo{
+					PeerAddr: net.IPNet{
+						IP:   net.ParseIP(peer.PrimaryAddress()),
+						Mask: getCIDRMaskFromAddr(peer.PrimaryAddress()),
+					},
+					PeerKey: peerHost.PublicKey.String(),
+					Allow:   true,
+				}
+			}
 
 			if _, ok := hostPeerUpdate.PeerIDs[peerHost.PublicKey.String()]; !ok {
 				hostPeerUpdate.PeerIDs[peerHost.PublicKey.String()] = make(map[string]models.IDandAddr)
@@ -408,7 +429,7 @@ func GetPeerUpdateForHost(host *models.Host) (models.HostPeerUpdate, error) {
 
 		}
 		if node.IsIngressGateway {
-			extPeers, extPeerIDAndAddrs, err := getExtPeers(&node, true)
+			extPeers, extPeerIDAndAddrs, err := getExtPeers(&node)
 			if err == nil {
 				hostPeerUpdate.Peers = append(hostPeerUpdate.Peers, extPeers...)
 				for _, extPeerIdAndAddr := range extPeerIDAndAddrs {
@@ -419,6 +440,19 @@ func GetPeerUpdateForHost(host *models.Host) (models.HostPeerUpdate, error) {
 						Name:    extPeerIdAndAddr.Name,
 						Network: node.Network,
 					}
+					hostPeerUpdate.IngressInfo.ExtPeers[extPeerIdAndAddr.ID] = models.ExtClientInfo{
+						Masquerade: true,
+						IngGwAddr: net.IPNet{
+							IP:   net.ParseIP(node.PrimaryAddress()),
+							Mask: getCIDRMaskFromAddr(node.PrimaryAddress()),
+						},
+						ExtPeerAddr: net.IPNet{
+							IP:   net.ParseIP(extPeerIdAndAddr.Address),
+							Mask: getCIDRMaskFromAddr(extPeerIdAndAddr.Address),
+						},
+						ExtPeerKey: extPeerIdAndAddr.ID,
+						Peers:      extClientPeerMap,
+					}
 				}
 
 			} else if !database.IsEmptyRecord(err) {
@@ -530,21 +564,21 @@ func GetPeerUpdate(node *models.Node, host *models.Host) (models.PeerUpdate, err
 	return peerUpdate, nil
 }
 
-func getRelayAllowedIPs(node, peer *models.Node) []net.IPNet {
-	var allowedips []net.IPNet
-	var allowedip net.IPNet
-	for _, addr := range peer.RelayAddrs {
-		if node.Address.IP.String() == addr {
-			continue
-		}
-		if node.Address6.IP.String() == addr {
-			continue
-		}
-		allowedip.IP = net.ParseIP(addr)
-		allowedips = append(allowedips, allowedip)
-	}
-	return allowedips
-}
+// func getRelayAllowedIPs(node, peer *models.Node) []net.IPNet {
+// 	var allowedips []net.IPNet
+// 	var allowedip net.IPNet
+// 	for _, addr := range peer.RelayAddrs {
+// 		if node.Address.IP.String() == addr {
+// 			continue
+// 		}
+// 		if node.Address6.IP.String() == addr {
+// 			continue
+// 		}
+// 		allowedip.IP = net.ParseIP(addr)
+// 		allowedips = append(allowedips, allowedip)
+// 	}
+// 	return allowedips
+// }
 
 // GetPeerUpdateLegacy - gets a wireguard peer config for each peer of a node
 func GetPeerUpdateLegacy(node *models.Node) (models.PeerUpdate, error) {
@@ -699,7 +733,7 @@ func GetPeerUpdateLegacy(node *models.Node) (models.PeerUpdate, error) {
 
 	}
 	if node.IsIngressGateway {
-		extPeers, idsAndAddr, err := getExtPeers(node, true)
+		extPeers, idsAndAddr, err := getExtPeers(node)
 		if err == nil {
 			peers = append(peers, extPeers...)
 			for i := range idsAndAddr {
@@ -722,7 +756,7 @@ func GetPeerUpdateLegacy(node *models.Node) (models.PeerUpdate, error) {
 	return peerUpdate, nil
 }
 
-func getExtPeers(node *models.Node, forIngressNode bool) ([]wgtypes.PeerConfig, []models.IDandAddr, error) {
+func getExtPeers(node *models.Node) ([]wgtypes.PeerConfig, []models.IDandAddr, error) {
 	var peers []wgtypes.PeerConfig
 	var idsAndAddr []models.IDandAddr
 	extPeers, err := GetNetworkExtClients(node.Network)
@@ -740,13 +774,14 @@ func getExtPeers(node *models.Node, forIngressNode bool) ([]wgtypes.PeerConfig,
 			continue
 		}
 
-		if host.PublicKey.String() == extPeer.PublicKey {
+		if host.PublicKey.String() == extPeer.PublicKey ||
+			extPeer.IngressGatewayID != node.ID.String() || !extPeer.Enabled {
 			continue
 		}
 
 		var allowedips []net.IPNet
 		var peer wgtypes.PeerConfig
-		if forIngressNode && extPeer.Address != "" {
+		if extPeer.Address != "" {
 			var peeraddr = net.IPNet{
 				IP:   net.ParseIP(extPeer.Address),
 				Mask: net.CIDRMask(32, 32),
@@ -756,7 +791,7 @@ func getExtPeers(node *models.Node, forIngressNode bool) ([]wgtypes.PeerConfig,
 			}
 		}
 
-		if forIngressNode && extPeer.Address6 != "" {
+		if extPeer.Address6 != "" {
 			var addr6 = net.IPNet{
 				IP:   net.ParseIP(extPeer.Address6),
 				Mask: net.CIDRMask(128, 128),
@@ -765,26 +800,6 @@ func getExtPeers(node *models.Node, forIngressNode bool) ([]wgtypes.PeerConfig,
 				allowedips = append(allowedips, addr6)
 			}
 		}
-		if !forIngressNode {
-			if extPeer.InternalIPAddr != "" {
-				peerInternalAddr := net.IPNet{
-					IP:   net.ParseIP(extPeer.InternalIPAddr),
-					Mask: net.CIDRMask(32, 32),
-				}
-				if peerInternalAddr.IP != nil && peerInternalAddr.Mask != nil {
-					allowedips = append(allowedips, peerInternalAddr)
-				}
-			}
-			if extPeer.InternalIPAddr6 != "" {
-				peerInternalAddr6 := net.IPNet{
-					IP:   net.ParseIP(extPeer.InternalIPAddr6),
-					Mask: net.CIDRMask(32, 32),
-				}
-				if peerInternalAddr6.IP != nil && peerInternalAddr6.Mask != nil {
-					allowedips = append(allowedips, peerInternalAddr6)
-				}
-			}
-		}
 
 		primaryAddr := extPeer.Address
 		if primaryAddr == "" {
@@ -806,7 +821,7 @@ func getExtPeers(node *models.Node, forIngressNode bool) ([]wgtypes.PeerConfig,
 
 }
 
-func getExtPeersForProxy(node *models.Node, proxyPeerConf map[string]proxy_models.PeerConf) ([]wgtypes.PeerConfig, map[string]proxy_models.PeerConf, error) {
+func getExtPeersForProxy(node *models.Node, proxyPeerConf map[string]models.PeerConf) ([]wgtypes.PeerConfig, map[string]models.PeerConf, error) {
 	var peers []wgtypes.PeerConfig
 	host, err := GetHost(node.HostID.String())
 	if err != nil {
@@ -824,7 +839,8 @@ func getExtPeersForProxy(node *models.Node, proxyPeerConf map[string]proxy_model
 			continue
 		}
 
-		if host.PublicKey.String() == extPeer.PublicKey {
+		if host.PublicKey.String() == extPeer.PublicKey ||
+			extPeer.IngressGatewayID != node.ID.String() || !extPeer.Enabled {
 			continue
 		}
 
@@ -855,14 +871,9 @@ func getExtPeersForProxy(node *models.Node, proxyPeerConf map[string]proxy_model
 			ReplaceAllowedIPs: true,
 			AllowedIPs:        allowedips,
 		}
-		extInternalPrimaryAddr := extPeer.InternalIPAddr
-		if extInternalPrimaryAddr == "" {
-			extInternalPrimaryAddr = extPeer.InternalIPAddr6
-		}
-		extConf := proxy_models.PeerConf{
-			IsExtClient:   true,
-			Address:       net.ParseIP(extPeer.Address),
-			ExtInternalIp: net.ParseIP(extInternalPrimaryAddr),
+		extConf := models.PeerConf{
+			IsExtClient: true,
+			Address:     net.ParseIP(extPeer.Address),
 		}
 		proxyPeerConf[peer.PublicKey.String()] = extConf
 
@@ -879,7 +890,7 @@ func GetAllowedIPs(node, peer *models.Node, metrics *models.Metrics) []net.IPNet
 
 	// handle ingress gateway peers
 	if peer.IsIngressGateway {
-		extPeers, _, err := getExtPeers(peer, false)
+		extPeers, _, err := getExtPeers(peer)
 		if err != nil {
 			logger.Log(2, "could not retrieve ext peers for ", peer.ID.String(), err.Error())
 		}
@@ -1057,7 +1068,7 @@ func GetPeerUpdateForRelayedNode(node *models.Node, udppeers map[string]string)
 	peers = append(peers, peerData)
 	//if ingress add extclients
 	if node.IsIngressGateway {
-		extPeers, _, err := getExtPeers(node, true)
+		extPeers, _, err := getExtPeers(node)
 		if err == nil {
 			peers = append(peers, extPeers...)
 		} else {
@@ -1140,3 +1151,15 @@ func getNodeAllowedIPs(peer, node *models.Node) []net.IPNet {
 	}
 	return allowedips
 }
+
+func getCIDRMaskFromAddr(addr string) net.IPMask {
+	cidr := net.CIDRMask(32, 32)
+	ipAddr, err := netip.ParseAddr(addr)
+	if err != nil {
+		return cidr
+	}
+	if ipAddr.Is6() {
+		cidr = net.CIDRMask(128, 128)
+	}
+	return cidr
+}

+ 10 - 4
logic/pro/networkuser_test.go

@@ -3,6 +3,7 @@ package pro
 import (
 	"testing"
 
+	"github.com/google/uuid"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models/promodels"
@@ -18,8 +19,13 @@ func TestNetworkUserLogic(t *testing.T) {
 		NetID:        "skynet",
 		AddressRange: "192.168.0.0/24",
 	}
-	nodes := []models.LegacyNode{
-		models.LegacyNode{ID: "coolnode"},
+	tmpCNode := models.CommonNode{
+		ID: uuid.New(),
+	}
+	tempNode := models.Node{}
+	tempNode.CommonNode = tmpCNode
+	nodes := []models.Node{
+		tempNode,
 	}
 
 	clients := []models.ExtClient{
@@ -63,10 +69,10 @@ func TestNetworkUserLogic(t *testing.T) {
 	})
 
 	t.Run("Successful net user node isallowed", func(t *testing.T) {
-		networkUser.Nodes = append(networkUser.Nodes, "coolnode")
+		networkUser.Nodes = append(networkUser.Nodes, nodes[0].ID.String())
 		err := UpdateNetworkUser(network.NetID, &networkUser)
 		assert.Nil(t, err)
-		isUserNodeAllowed := IsUserNodeAllowed(nodes[:], network.NetID, string(networkUser.ID), "coolnode")
+		isUserNodeAllowed := IsUserNodeAllowed(nodes[:], network.NetID, string(networkUser.ID), nodes[0].ID.String())
 		assert.True(t, isUserNodeAllowed)
 	})
 

+ 0 - 8
logic/server.go

@@ -1,8 +1,6 @@
 package logic
 
 import (
-	"strings"
-
 	"github.com/google/uuid"
 	"github.com/gravitl/netmaker/models"
 )
@@ -33,9 +31,3 @@ func EnterpriseCheck() {
 		check()
 	}
 }
-
-// == Private ==
-
-func isDeleteError(err error) bool {
-	return err != nil && strings.Contains(err.Error(), models.NODE_DELETE)
-}

+ 0 - 3
logic/serverconf.go

@@ -19,9 +19,6 @@ var (
 	Free_Tier = false
 )
 
-// constant for database key for storing server ids
-const server_id_key = "nm-server-id"
-
 type serverData struct {
 	PrivateKey string `json:"privatekey,omitempty" bson:"privatekey,omitempty"`
 }

+ 4 - 58
logic/util.go

@@ -5,7 +5,6 @@ import (
 	crand "crypto/rand"
 	"encoding/base64"
 	"encoding/json"
-	"fmt"
 	"math/big"
 	"math/rand"
 	"net"
@@ -15,8 +14,6 @@ import (
 
 	"github.com/c-robinson/iplib"
 	"github.com/gravitl/netmaker/database"
-	"github.com/gravitl/netmaker/logger"
-	"github.com/gravitl/netmaker/netclient/ncutils"
 )
 
 // IsBase64 - checks if a string is in base64 format
@@ -42,26 +39,12 @@ func FileExists(f string) bool {
 }
 
 // IsAddressInCIDR - util to see if an address is in a cidr or not
-func IsAddressInCIDR(address, cidr string) bool {
+func IsAddressInCIDR(address net.IP, cidr string) bool {
 	var _, currentCIDR, cidrErr = net.ParseCIDR(cidr)
 	if cidrErr != nil {
 		return false
 	}
-	var addrParts = strings.Split(address, ".")
-	var addrPartLength = len(addrParts)
-	if addrPartLength != 4 {
-		return false
-	} else {
-		if addrParts[addrPartLength-1] == "0" ||
-			addrParts[addrPartLength-1] == "255" {
-			return false
-		}
-	}
-	ip, _, err := net.ParseCIDR(fmt.Sprintf("%s/32", address))
-	if err != nil {
-		return false
-	}
-	return currentCIDR.Contains(ip)
+	return currentCIDR.Contains(address)
 }
 
 // SetNetworkNodesLastModified - sets the network nodes last modified
@@ -113,26 +96,6 @@ func RandomString(length int) string {
 	return string(b)
 }
 
-// == Private Methods ==
-
-func setIPForwardingLinux() error {
-	out, err := ncutils.RunCmd("sysctl net.ipv4.ip_forward", true)
-	if err != nil {
-		logger.Log(0, "WARNING: Error encountered setting ip forwarding. This can break functionality.")
-		return err
-	} else {
-		s := strings.Fields(string(out))
-		if s[2] != "1" {
-			_, err = ncutils.RunCmd("sysctl -w net.ipv4.ip_forward=1", true)
-			if err != nil {
-				logger.Log(0, "WARNING: Error encountered setting ip forwarding. You may want to investigate this.")
-				return err
-			}
-		}
-	}
-	return nil
-}
-
 // StringSliceContains - sees if a string slice contains a string element
 func StringSliceContains(slice []string, item string) bool {
 	for _, s := range slice {
@@ -143,8 +106,6 @@ func StringSliceContains(slice []string, item string) bool {
 	return false
 }
 
-// == private ==
-
 // NormalCIDR - returns the first address of CIDR
 func NormalizeCIDR(address string) (string, error) {
 	ip, IPNet, err := net.ParseCIDR(address)
@@ -161,23 +122,6 @@ func NormalizeCIDR(address string) (string, error) {
 	return IPNet.String(), nil
 }
 
-func getNetworkProtocols(cidrs []string) (bool, bool) {
-	ipv4 := false
-	ipv6 := false
-	for _, cidr := range cidrs {
-		ip, _, err := net.ParseCIDR(cidr)
-		if err != nil {
-			continue
-		}
-		if ip.To4() == nil {
-			ipv6 = true
-		} else {
-			ipv4 = true
-		}
-	}
-	return ipv4, ipv6
-}
-
 // StringDifference - returns the elements in `a` that aren't in `b`.
 func StringDifference(a, b []string) []string {
 	mb := make(map[string]struct{}, len(b))
@@ -206,3 +150,5 @@ func CheckIfFileExists(filePath string) bool {
 func RemoveStringSlice(slice []string, i int) []string {
 	return append(slice[:i], slice[i+1:]...)
 }
+
+// == private ==

+ 8 - 6
logic/zombie.go

@@ -25,6 +25,7 @@ var (
 
 // CheckZombies - checks if new node has same macaddress as existing node
 // if so, existing node is added to zombie node quarantine list
+// also cleans up nodes past their expiration date
 func CheckZombies(newnode *models.Node, mac net.HardwareAddr) {
 	nodes, err := GetNetworkNodes(newnode.Network)
 	if err != nil {
@@ -32,12 +33,11 @@ func CheckZombies(newnode *models.Node, mac net.HardwareAddr) {
 		return
 	}
 	for _, node := range nodes {
-		host, err := GetHost(node.HostID.String())
-		if err != nil {
-			// should we delete the node if host not found ??
+		if node.ID == newnode.ID {
+			//skip self
 			continue
 		}
-		if host.MacAddress.String() == mac.String() {
+		if node.HostID == newnode.HostID || time.Now().After(node.ExpirationDateTime) {
 			logger.Log(0, "adding ", node.ID.String(), " to zombie list")
 			newZombie <- node.ID
 		}
@@ -45,7 +45,7 @@ func CheckZombies(newnode *models.Node, mac net.HardwareAddr) {
 }
 
 // ManageZombies - goroutine which adds/removes/deletes nodes from the zombie node quarantine list
-func ManageZombies(ctx context.Context) {
+func ManageZombies(ctx context.Context, peerUpdate chan *models.Node) {
 	logger.Log(2, "Zombie management started")
 	InitializeZombies()
 	for {
@@ -80,11 +80,13 @@ func ManageZombies(ctx context.Context) {
 						zombies = append(zombies[:i], zombies[i+1:]...)
 						continue
 					}
-					if time.Since(node.LastCheckIn) > time.Minute*ZOMBIE_DELETE_TIME {
+					if time.Since(node.LastCheckIn) > time.Minute*ZOMBIE_DELETE_TIME || time.Now().After(node.ExpirationDateTime) {
 						if err := DeleteNode(&node, true); err != nil {
 							logger.Log(1, "error deleting zombie node", zombies[i].String(), err.Error())
 							continue
 						}
+						node.Action = models.NODE_DELETE
+						peerUpdate <- &node
 						logger.Log(1, "deleting zombie node", node.ID.String())
 						zombies = append(zombies[:i], zombies[i+1:]...)
 					}

+ 9 - 7
main.go

@@ -110,12 +110,6 @@ func initialize() { // Client Mode Prereq Check
 			logger.FatalLog("To run in client mode requires root privileges. Either disable client mode or run with sudo.")
 		}
 	}
-	// initialize iptables to ensure gateways work correctly and mq is forwarded if containerized
-	if servercfg.ManageIPTables() != "off" {
-		if err = serverctl.InitIPTables(true); err != nil {
-			logger.FatalLog("Unable to initialize iptables on host:", err.Error())
-		}
-	}
 
 	if servercfg.IsDNSMode() {
 		err := functions.SetDNSDir()
@@ -191,7 +185,15 @@ func runMessageQueue(wg *sync.WaitGroup) {
 	mq.SetupMQTT()
 	ctx, cancel := context.WithCancel(context.Background())
 	go mq.Keepalive(ctx)
-	go logic.ManageZombies(ctx)
+	go func() {
+		peerUpdate := make(chan *models.Node)
+		go logic.ManageZombies(ctx, peerUpdate)
+		for nodeUpdate := range peerUpdate {
+			if err := mq.NodeUpdate(nodeUpdate); err != nil {
+				logger.Log(0, "failed to send peer update for deleted node: ", nodeUpdate.ID.String(), err.Error())
+			}
+		}
+	}()
 	go logic.PurgePendingNodes(ctx)
 	quit := make(chan os.Signal, 1)
 	signal.Notify(quit, syscall.SIGTERM, os.Interrupt)

+ 111 - 0
metrics/metrics.go

@@ -0,0 +1,111 @@
+package metrics
+
+import (
+	"fmt"
+	"sync"
+	"time"
+
+	"github.com/go-ping/ping"
+	"github.com/gravitl/netmaker/logger"
+	"github.com/gravitl/netmaker/models"
+)
+
+// lock for metrics map
+var metricsMapLock = &sync.RWMutex{}
+
+// metrics data map
+var metricsPeerMap = make(map[string]map[string]*models.ProxyMetric)
+
+// GetMetricByServer - get metric data of peers by server
+func GetMetricByServer(server string) map[string]*models.ProxyMetric {
+	metricsMapLock.RLock()
+	defer metricsMapLock.RUnlock()
+	if _, ok := metricsPeerMap[server]; !ok {
+		return nil
+	}
+	return metricsPeerMap[server]
+}
+
+// GetMetric - fetches the metric data for the peer
+func GetMetric(server, peerKey string) models.ProxyMetric {
+	metric := models.ProxyMetric{}
+	peerMetricMap := GetMetricByServer(server)
+	metricsMapLock.RLock()
+	defer metricsMapLock.RUnlock()
+	if peerMetricMap == nil {
+		return metric
+	}
+	if m, ok := peerMetricMap[peerKey]; ok && m != nil {
+		metric = *m
+	}
+	return metric
+}
+
+// UpdateMetric - updates metric data for the peer
+func UpdateMetric(server, peerKey string, metric *models.ProxyMetric) {
+	metricsMapLock.Lock()
+	defer metricsMapLock.Unlock()
+	if metricsPeerMap[server] == nil {
+		metricsPeerMap[server] = make(map[string]*models.ProxyMetric)
+	}
+	metricsPeerMap[server][peerKey] = metric
+}
+
+// UpdateMetricByPeer - updates metrics data by peer public key
+func UpdateMetricByPeer(peerKey string, metric *models.ProxyMetric, onlyTraffic bool) {
+	metricsMapLock.Lock()
+	defer metricsMapLock.Unlock()
+	for server, peerKeyMap := range metricsPeerMap {
+		if peerMetric, ok := peerKeyMap[peerKey]; ok {
+			peerMetric.TrafficRecieved += metric.TrafficRecieved
+			peerMetric.TrafficSent += metric.TrafficSent
+			if !onlyTraffic {
+				peerMetric.LastRecordedLatency = metric.LastRecordedLatency
+			}
+
+			metricsPeerMap[server][peerKey] = peerMetric
+		}
+	}
+}
+
+// ResetMetricsForPeer - reset metrics for peer
+func ResetMetricsForPeer(server, peerKey string) {
+	metricsMapLock.Lock()
+	defer metricsMapLock.Unlock()
+	delete(metricsPeerMap[server], peerKey)
+}
+
+// ResetMetricForNode - resets node level metrics
+func ResetMetricForNode(server, peerKey, peerID string) {
+	metric := GetMetric(server, peerKey)
+	delete(metric.NodeConnectionStatus, peerID)
+	UpdateMetric(server, peerKey, &metric)
+}
+
+// MetricCollectionInterval - collection interval for metrics
+const MetricCollectionInterval = time.Second * 25
+
+// PeerConnectionStatus - get peer connection status by pinging
+func PeerConnectionStatus(address string) (connected bool) {
+	fmt.Println("PINGER ADDR: ", address)
+	pinger, err := ping.NewPinger(address)
+	if err != nil {
+		logger.Log(0, "could not initiliaze ping peer address", address, err.Error())
+		connected = false
+	} else {
+		pinger.Timeout = time.Second * 2
+		err = pinger.Run()
+		if err != nil {
+			logger.Log(0, "failed to ping on peer address", address, err.Error())
+			return false
+		} else {
+			pingStats := pinger.Statistics()
+			if pingStats.PacketsRecv > 0 {
+				connected = true
+				return
+			}
+		}
+	}
+
+	return
+}

+ 2 - 3
models/accessToken.go

@@ -8,7 +8,6 @@ type AccessToken struct {
 
 // ClientConfig - the config of the client
 type ClientConfig struct {
-	Network    string `json:"network"`
-	Key        string `json:"key"`
-	LocalRange string `json:"localrange"`
+	Network string `json:"network"`
+	Key     string `json:"key"`
 }

+ 2 - 13
models/api_host.go

@@ -13,9 +13,9 @@ type ApiHost struct {
 	Debug            bool     `json:"debug"`
 	IsStatic         bool     `json:"isstatic"`
 	ListenPort       int      `json:"listenport"`
-	LocalRange       string   `json:"localrange"`
 	LocalListenPort  int      `json:"locallistenport"`
 	ProxyListenPort  int      `json:"proxy_listen_port"`
+	PublicListenPort int      `json:"public_listen_port" yaml:"public_listen_port"`
 	MTU              int      `json:"mtu" yaml:"mtu"`
 	Interfaces       []Iface  `json:"interfaces" yaml:"interfaces"`
 	DefaultInterface string   `json:"defaultinterface" yaml:"defautlinterface"`
@@ -50,16 +50,13 @@ func (h *Host) ConvertNMHostToAPI() *ApiHost {
 	}
 	a.IsStatic = h.IsStatic
 	a.ListenPort = h.ListenPort
-	a.LocalRange = h.LocalRange.String()
-	if isEmptyAddr(a.LocalRange) {
-		a.LocalRange = ""
-	}
 	a.MTU = h.MTU
 	a.MacAddress = h.MacAddress.String()
 	a.Name = h.Name
 	a.OS = h.OS
 	a.Nodes = h.Nodes
 	a.ProxyEnabled = h.ProxyEnabled
+	a.PublicListenPort = h.PublicListenPort
 	a.ProxyListenPort = h.ProxyListenPort
 	a.PublicKey = h.PublicKey.String()
 	a.Verbosity = h.Verbosity
@@ -106,14 +103,6 @@ func (a *ApiHost) ConvertAPIHostToNMHost(currentHost *Host) *Host {
 	h.RelayedHosts = a.RelayedHosts
 	h.IsRelay = a.IsRelay
 	h.IsRelayed = a.IsRelayed
-	if len(a.LocalRange) > 0 {
-		_, localRange, err := net.ParseCIDR(a.LocalRange)
-		if err == nil {
-			h.LocalRange = *localRange
-		}
-	} else if !isEmptyAddr(currentHost.LocalRange.String()) {
-		h.LocalRange = currentHost.LocalRange
-	}
 	h.ProxyEnabled = a.ProxyEnabled
 	h.IsDefault = a.IsDefault
 

+ 3 - 8
models/api_node.go

@@ -14,8 +14,6 @@ type ApiNode struct {
 	Address                 string   `json:"address" validate:"omitempty,ipv4"`
 	Address6                string   `json:"address6" validate:"omitempty,ipv6"`
 	LocalAddress            string   `json:"localaddress" validate:"omitempty,ipv4"`
-	PostUp                  string   `json:"postup"`
-	PostDown                string   `json:"postdown"`
 	AllowedIPs              []string `json:"allowedips"`
 	PersistentKeepalive     int32    `json:"persistentkeepalive"`
 	LastModified            int64    `json:"lastmodified"`
@@ -53,8 +51,6 @@ func (a *ApiNode) ConvertToServerNode(currentNode *Node) *Node {
 	convertedNode.Connected = a.Connected
 	convertedNode.ID, _ = uuid.Parse(a.ID)
 	convertedNode.HostID, _ = uuid.Parse(a.HostID)
-	convertedNode.PostUp = a.PostUp
-	convertedNode.PostDown = a.PostDown
 	convertedNode.IsLocal = a.IsLocal
 	convertedNode.IsRelay = a.IsRelay
 	convertedNode.IsRelayed = a.IsRelayed
@@ -99,8 +95,8 @@ func (a *ApiNode) ConvertToServerNode(currentNode *Node) *Node {
 	}
 	ip6, addr6, err := net.ParseCIDR(a.Address6)
 	if err == nil {
-		convertedNode.Address = *addr6
-		convertedNode.Address.IP = ip6
+		convertedNode.Address6 = *addr6
+		convertedNode.Address6.IP = ip6
 	}
 	convertedNode.FailoverNode, _ = uuid.Parse(a.FailoverNode)
 	convertedNode.LastModified = time.Unix(a.LastModified, 0)
@@ -127,12 +123,11 @@ func (nm *Node) ConvertToAPINode() *ApiNode {
 	if isEmptyAddr(apiNode.LocalAddress) {
 		apiNode.LocalAddress = ""
 	}
-	apiNode.PostDown = nm.PostDown
-	apiNode.PostUp = nm.PostUp
 	apiNode.PersistentKeepalive = int32(nm.PersistentKeepalive.Seconds())
 	apiNode.LastModified = nm.LastModified.Unix()
 	apiNode.LastCheckIn = nm.LastCheckIn.Unix()
 	apiNode.LastPeerUpdate = nm.LastPeerUpdate.Unix()
+	apiNode.ExpirationDateTime = nm.ExpirationDateTime.Unix()
 	apiNode.Network = nm.Network
 	apiNode.NetworkRange = nm.NetworkRange.String()
 	if isEmptyAddr(apiNode.NetworkRange) {

+ 1 - 1
models/dnsEntry.go

@@ -1,4 +1,4 @@
-//TODO:  Either add a returnNetwork and returnKey, or delete this
+// TODO:  Either add a returnNetwork and returnKey, or delete this
 package models
 
 // DNSEntry - a DNS entry represented as struct

+ 0 - 2
models/extclient.go

@@ -14,6 +14,4 @@ type ExtClient struct {
 	LastModified           int64  `json:"lastmodified" bson:"lastmodified"`
 	Enabled                bool   `json:"enabled" bson:"enabled"`
 	OwnerID                string `json:"ownerid" bson:"ownerid"`
-	InternalIPAddr         string `json:"internal_ip_addr" bson:"internal_ip_addr"`
-	InternalIPAddr6        string `json:"internal_ip_addr6" bson:"internal_ip_addr6"`
 }

+ 0 - 2
models/host.go

@@ -24,8 +24,6 @@ type Host struct {
 	Interface        string           `json:"interface" yaml:"interface"`
 	Debug            bool             `json:"debug" yaml:"debug"`
 	ListenPort       int              `json:"listenport" yaml:"listenport"`
-	LocalAddress     net.IPNet        `json:"localaddress" yaml:"localaddress"`
-	LocalRange       net.IPNet        `json:"localrange" yaml:"localrange"`
 	PublicListenPort int              `json:"public_listen_port" yaml:"public_listen_port"`
 	ProxyListenPort  int              `json:"proxy_listen_port" yaml:"proxy_listen_port"`
 	MTU              int              `json:"mtu" yaml:"mtu"`

+ 8 - 0
models/migrate.go

@@ -0,0 +1,8 @@
+package models
+
+// MigrationData struct needed to create new v0.18.0 node from v.0.17.X node
+type MigrationData struct {
+	JoinData     JoinData
+	LegacyNodeID string
+	Password     string
+}

+ 39 - 15
models/mqtt.go

@@ -1,30 +1,54 @@
 package models
 
 import (
-	proxy_models "github.com/gravitl/netclient/nmproxy/models"
+	"net"
+
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 
 // PeerUpdate - struct
 type PeerUpdate struct {
-	Network       string                           `json:"network" bson:"network" yaml:"network"`
-	ServerVersion string                           `json:"serverversion" bson:"serverversion" yaml:"serverversion"`
-	ServerAddrs   []ServerAddr                     `json:"serveraddrs" bson:"serveraddrs" yaml:"serveraddrs"`
-	Peers         []wgtypes.PeerConfig             `json:"peers" bson:"peers" yaml:"peers"`
-	DNS           string                           `json:"dns" bson:"dns" yaml:"dns"`
-	PeerIDs       PeerMap                          `json:"peerids" bson:"peerids" yaml:"peerids"`
-	ProxyUpdate   proxy_models.ProxyManagerPayload `json:"proxy_update" bson:"proxy_update" yaml:"proxy_update"`
+	Network       string               `json:"network" bson:"network" yaml:"network"`
+	ServerVersion string               `json:"serverversion" bson:"serverversion" yaml:"serverversion"`
+	ServerAddrs   []ServerAddr         `json:"serveraddrs" bson:"serveraddrs" yaml:"serveraddrs"`
+	Peers         []wgtypes.PeerConfig `json:"peers" bson:"peers" yaml:"peers"`
+	DNS           string               `json:"dns" bson:"dns" yaml:"dns"`
+	PeerIDs       PeerMap              `json:"peerids" bson:"peerids" yaml:"peerids"`
+	ProxyUpdate   ProxyManagerPayload  `json:"proxy_update" bson:"proxy_update" yaml:"proxy_update"`
 }
 
 // HostPeerUpdate - struct for host peer updates
 type HostPeerUpdate struct {
-	Host          Host                             `json:"host" bson:"host" yaml:"host"`
-	ServerVersion string                           `json:"serverversion" bson:"serverversion" yaml:"serverversion"`
-	ServerAddrs   []ServerAddr                     `json:"serveraddrs" bson:"serveraddrs" yaml:"serveraddrs"`
-	Network       map[string]NetworkInfo           `json:"network" bson:"network" yaml:"network"`
-	Peers         []wgtypes.PeerConfig             `json:"peers" bson:"peers" yaml:"peers"`
-	PeerIDs       HostPeerMap                      `json:"peerids" bson:"peerids" yaml:"peerids"`
-	ProxyUpdate   proxy_models.ProxyManagerPayload `json:"proxy_update" bson:"proxy_update" yaml:"proxy_update"`
+	Host          Host                   `json:"host" bson:"host" yaml:"host"`
+	Server        string                 `json:"server" bson:"server" yaml:"server"`
+	ServerVersion string                 `json:"serverversion" bson:"serverversion" yaml:"serverversion"`
+	ServerAddrs   []ServerAddr           `json:"serveraddrs" bson:"serveraddrs" yaml:"serveraddrs"`
+	Network       map[string]NetworkInfo `json:"network" bson:"network" yaml:"network"`
+	Peers         []wgtypes.PeerConfig   `json:"peers" bson:"peers" yaml:"peers"`
+	PeerIDs       HostPeerMap            `json:"peerids" bson:"peerids" yaml:"peerids"`
+	ProxyUpdate   ProxyManagerPayload    `json:"proxy_update" bson:"proxy_update" yaml:"proxy_update"`
+	IngressInfo   IngressInfo            `json:"ingress_info" bson:"ext_peers" yaml:"ext_peers"`
+}
+
+// IngressInfo - struct for ingress info
+type IngressInfo struct {
+	ExtPeers map[string]ExtClientInfo `json:"ext_peers" yaml:"ext_peers"`
+}
+
+// PeerExtInfo - struct for peer info for an ext. client
+type PeerExtInfo struct {
+	PeerAddr net.IPNet `json:"peer_addr" yaml:"peer_addr"`
+	PeerKey  string    `json:"peer_key" yaml:"peer_key"`
+	Allow    bool      `json:"allow" yaml:"allow"`
+}
+
+// ExtClientInfo - struct for ext. client and it's peers
+type ExtClientInfo struct {
+	IngGwAddr   net.IPNet              `json:"ingress_gw_addr" yaml:"ingress_gw_addr"`
+	Masquerade  bool                   `json:"masquerade" yaml:"masquerade"`
+	ExtPeerAddr net.IPNet              `json:"ext_peer_addr" yaml:"ext_peer_addr"`
+	ExtPeerKey  string                 `json:"ext_peer_key" yaml:"ext_peer_key"`
+	Peers       map[string]PeerExtInfo `json:"peers" yaml:"peers"`
 }
 
 // NetworkInfo - struct for network info

+ 1 - 7
models/network.go

@@ -7,7 +7,7 @@ import (
 )
 
 // Network Struct - contains info for a given unique network
-//At  some point, need to replace all instances of Name with something else like  Identifier
+// At  some point, need to replace all instances of Name with something else like  Identifier
 type Network struct {
 	AddressRange        string                `json:"addressrange" bson:"addressrange" validate:"omitempty,cidrv4"`
 	AddressRange6       string                `json:"addressrange6" bson:"addressrange6" validate:"omitempty,cidrv6"`
@@ -17,7 +17,6 @@ type Network struct {
 	DefaultInterface    string                `json:"defaultinterface" bson:"defaultinterface" validate:"min=1,max=15"`
 	DefaultListenPort   int32                 `json:"defaultlistenport,omitempty" bson:"defaultlistenport,omitempty" validate:"omitempty,min=1024,max=65535"`
 	NodeLimit           int32                 `json:"nodelimit" bson:"nodelimit"`
-	DefaultPostUp       string                `json:"defaultpostup" bson:"defaultpostup"`
 	DefaultPostDown     string                `json:"defaultpostdown" bson:"defaultpostdown"`
 	DefaultKeepalive    int32                 `json:"defaultkeepalive" bson:"defaultkeepalive" validate:"omitempty,max=1000"`
 	AccessKeys          []AccessKey           `json:"accesskeys" bson:"accesskeys"`
@@ -25,8 +24,6 @@ type Network struct {
 	IsLocal             string                `json:"islocal" bson:"islocal" validate:"checkyesorno"`
 	IsIPv4              string                `json:"isipv4" bson:"isipv4" validate:"checkyesorno"`
 	IsIPv6              string                `json:"isipv6" bson:"isipv6" validate:"checkyesorno"`
-	IsPointToSite       string                `json:"ispointtosite" bson:"ispointtosite" validate:"checkyesorno"`
-	LocalRange          string                `json:"localrange" bson:"localrange" validate:"omitempty,cidr"`
 	DefaultUDPHolePunch string                `json:"defaultudpholepunch" bson:"defaultudpholepunch" validate:"checkyesorno"`
 	DefaultExtClientDNS string                `json:"defaultextclientdns" bson:"defaultextclientdns"`
 	DefaultMTU          int32                 `json:"defaultmtu" bson:"defaultmtu"`
@@ -57,9 +54,6 @@ func (network *Network) SetDefaults() {
 	if network.IsLocal == "" {
 		network.IsLocal = "no"
 	}
-	if network.IsPointToSite == "" {
-		network.IsPointToSite = "no"
-	}
 	if network.DefaultInterface == "" {
 		if len(network.NetID) < 13 {
 			network.DefaultInterface = "nm-" + network.NetID

+ 0 - 9
models/network_test.go

@@ -13,13 +13,4 @@ package models
 //		assert.Equal(t, "NetID is not editable", err.Error())
 //		t.Log(err, Range, local)
 //	})
-//	t.Run("LocalRange", func(t *testing.T) {
-//		var networkupdate models.Network
-//		//NetID needs to be set as it will be in updateNetwork
-//		networkupdate.NetID = "skynet"
-//		networkupdate.LocalRange = "192.168.0.1/24"
-//		Range, local, err := network.Update(&networkupdate)
-//		assert.Nil(t, err)
-//		t.Log(err, Range, local)
-//	})
 //}

+ 3 - 31
models/node.go

@@ -15,7 +15,7 @@ const (
 	// NODE_SERVER_NAME - the default server name
 	NODE_SERVER_NAME = "netmaker"
 	// TEN_YEARS_IN_SECONDS - ten years in seconds
-	TEN_YEARS_IN_SECONDS = 300000000
+	TEN_YEARS_IN_SECONDS = 315670000000000000
 	// MAX_NAME_LENGTH - max name length of node
 	MAX_NAME_LENGTH = 62
 	// == ACTIONS == (can only be set by server)
@@ -66,8 +66,6 @@ type CommonNode struct {
 	Connected           bool          `json:"connected" yaml:"connected"`
 	Address             net.IPNet     `json:"address" yaml:"address"`
 	Address6            net.IPNet     `json:"address6" yaml:"address6"`
-	PostUp              string        `json:"postup" yaml:"postup"`
-	PostDown            string        `json:"postdown" yaml:"postdown"`
 	Action              string        `json:"action" yaml:"action"`
 	LocalAddress        net.IPNet     `json:"localaddress" yaml:"localaddress"`
 	IsLocal             bool          `json:"islocal" yaml:"islocal"`
@@ -115,8 +113,6 @@ type LegacyNode struct {
 	ProxyListenPort         int32                `json:"proxy_listen_port" bson:"proxy_listen_port" yaml:"proxy_listen_port" validate:"numeric,min=0,max=65535"`
 	PublicKey               string               `json:"publickey" bson:"publickey" yaml:"publickey" validate:"required,base64"`
 	Endpoint                string               `json:"endpoint" bson:"endpoint" yaml:"endpoint" validate:"required,ip"`
-	PostUp                  string               `json:"postup" bson:"postup" yaml:"postup"`
-	PostDown                string               `json:"postdown" bson:"postdown" yaml:"postdown"`
 	AllowedIPs              []string             `json:"allowedips" bson:"allowedips" yaml:"allowedips"`
 	PersistentKeepalive     int32                `json:"persistentkeepalive" bson:"persistentkeepalive" yaml:"persistentkeepalive" validate:"omitempty,numeric,max=1000"`
 	IsHub                   string               `json:"ishub" bson:"ishub" yaml:"ishub" validate:"checkyesorno"`
@@ -150,7 +146,6 @@ type LegacyNode struct {
 	IsServer        string      `json:"isserver" bson:"isserver" yaml:"isserver" validate:"checkyesorno"`
 	Action          string      `json:"action" bson:"action" yaml:"action"`
 	IsLocal         string      `json:"islocal" bson:"islocal" yaml:"islocal" validate:"checkyesorno"`
-	LocalRange      string      `json:"localrange" bson:"localrange" yaml:"localrange"`
 	IPForwarding    string      `json:"ipforwarding" bson:"ipforwarding" yaml:"ipforwarding" validate:"checkyesorno"`
 	OS              string      `json:"os" bson:"os" yaml:"os"`
 	MTU             int32       `json:"mtu" bson:"mtu" yaml:"mtu"`
@@ -197,13 +192,8 @@ func (node *Node) PrimaryAddress() string {
 }
 
 // Node.SetDefaultConnected
-func (node *LegacyNode) SetDefaultConnected() {
-	if node.Connected == "" {
-		node.Connected = "yes"
-	}
-	if node.IsServer == "yes" {
-		node.Connected = "yes"
-	}
+func (node *Node) SetDefaultConnected() {
+	node.Connected = true
 }
 
 // Node.SetDefaultACL
@@ -374,12 +364,6 @@ func (newNode *Node) Fill(currentNode *Node) { // TODO add new field for nftable
 	if newNode.Address6.String() == "" {
 		newNode.Address6 = currentNode.Address6
 	}
-	if newNode.PostUp == "" {
-		newNode.PostUp = currentNode.PostUp
-	}
-	if newNode.PostDown == "" {
-		newNode.PostDown = currentNode.PostDown
-	}
 	if newNode.PersistentKeepalive < 0 {
 		newNode.PersistentKeepalive = currentNode.PersistentKeepalive
 	}
@@ -495,13 +479,6 @@ func (ln *LegacyNode) ConvertToNewNode() (*Host, *Node) {
 		host.HostPass = ln.Password
 		host.Name = ln.Name
 		host.ListenPort = int(ln.ListenPort)
-		if _, cidr, err := net.ParseCIDR(ln.LocalAddress); err == nil {
-			host.LocalRange = *cidr
-		} else {
-			if _, cidr, err := net.ParseCIDR(ln.LocalRange); err == nil {
-				host.LocalRange = *cidr
-			}
-		}
 		host.ProxyListenPort = int(ln.ProxyListenPort)
 		host.MTU = int(ln.MTU)
 		host.PublicKey, _ = wgtypes.ParseKey(ln.PublicKey)
@@ -540,8 +517,6 @@ func (ln *LegacyNode) ConvertToNewNode() (*Host, *Node) {
 			Mask: net.CIDRMask(128, 128),
 		}
 	}
-	node.PostUp = ln.PostUp
-	node.PostDown = ln.PostDown
 	node.Action = ln.Action
 	node.IsLocal = parseBool(ln.IsLocal)
 	node.IsEgressGateway = parseBool(ln.IsEgressGateway)
@@ -565,8 +540,6 @@ func (n *Node) Legacy(h *Host, s *ServerConfig, net *Network) *LegacyNode {
 	l.ProxyListenPort = int32(h.ProxyListenPort)
 	l.PublicKey = h.PublicKey.String()
 	l.Endpoint = h.EndpointIP.String()
-	l.PostUp = n.PostUp
-	l.PostDown = n.PostDown
 	//l.AllowedIPs =
 	l.AccessKey = ""
 	l.Interface = WIREGUARD_INTERFACE
@@ -594,7 +567,6 @@ func (n *Node) Legacy(h *Host, s *ServerConfig, net *Network) *LegacyNode {
 	l.DNSOn = formatBool(n.DNSOn)
 	l.Action = n.Action
 	l.IsLocal = formatBool(n.IsLocal)
-	l.LocalRange = h.LocalRange.String()
 	l.IPForwarding = formatBool(h.IPForwarding)
 	l.OS = h.OS
 	l.MTU = int32(h.MTU)

+ 68 - 0
models/proxy.go

@@ -0,0 +1,68 @@
+package models
+
+import (
+	"net"
+	"time"
+
+	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
+)
+
+// ProxyAction - type for proxy action
+type ProxyAction string
+
+const (
+	// default proxy port
+	NmProxyPort = 51722
+	// PersistentKeepaliveInterval - default keepalive for wg peer
+	DefaultPersistentKeepaliveInterval = time.Duration(time.Second * 20)
+
+	// ProxyUpdate - constant for proxy update action
+	ProxyUpdate ProxyAction = "PROXY_UPDATE"
+	// ProxyDeletePeers - constant for proxy delete peers action
+	ProxyDeletePeers ProxyAction = "PROXY_DELETE"
+	// ProxyDeleteAllPeers - constant for proxy delete all peers action
+	ProxyDeleteAllPeers ProxyAction = "PROXY_DELETE_ALL"
+	// NoProxy - constant for no ProxyAction
+	NoProxy ProxyAction = "NO_PROXY"
+)
+
+// RelayedConf - struct relayed peers config
+type RelayedConf struct {
+	RelayedPeerEndpoint *net.UDPAddr         `json:"relayed_peer_endpoint"`
+	RelayedPeerPubKey   string               `json:"relayed_peer_pub_key"`
+	Peers               []wgtypes.PeerConfig `json:"relayed_peers"`
+}
+
+// PeerConf - struct for peer config in the network
+type PeerConf struct {
+	Proxy            bool         `json:"proxy"`
+	PublicListenPort int32        `json:"public_listen_port"`
+	IsExtClient      bool         `json:"is_ext_client"`
+	Address          net.IP       `json:"address"`
+	ExtInternalIp    net.IP       `json:"ext_internal_ip"`
+	IsRelayed        bool         `json:"is_relayed"`
+	RelayedTo        *net.UDPAddr `json:"relayed_to"`
+}
+
+// ProxyManagerPayload - struct for proxy manager payload
+type ProxyManagerPayload struct {
+	Action        ProxyAction `json:"action"`
+	InterfaceName string      `json:"interface_name"`
+	Server        string      `json:"server"`
+	//WgAddr          string                 `json:"wg_addr"`
+	Peers           []wgtypes.PeerConfig   `json:"peers"`
+	PeerMap         map[string]PeerConf    `json:"peer_map"`
+	IsIngress       bool                   `json:"is_ingress"`
+	IsRelayed       bool                   `json:"is_relayed"`
+	RelayedTo       *net.UDPAddr           `json:"relayed_to"`
+	IsRelay         bool                   `json:"is_relay"`
+	RelayedPeerConf map[string]RelayedConf `json:"relayed_conf"`
+}
+
+// Metric - struct for metric data
+type ProxyMetric struct {
+	NodeConnectionStatus map[string]bool `json:"node_connection_status"`
+	LastRecordedLatency  uint64          `json:"last_recorded_latency"`
+	TrafficSent          int64           `json:"traffic_sent"`     // stored in MB
+	TrafficRecieved      int64           `json:"traffic_recieved"` // stored in MB
+}

+ 0 - 2
models/structs.go

@@ -161,8 +161,6 @@ type EgressGatewayRequest struct {
 	NatEnabled string   `json:"natenabled" bson:"natenabled"`
 	Ranges     []string `json:"ranges" bson:"ranges"`
 	Interface  string   `json:"interface" bson:"interface"`
-	PostUp     string   `json:"postup" bson:"postup"`
-	PostDown   string   `json:"postdown" bson:"postdown"`
 }
 
 // RelayRequest - relay request struct

+ 13 - 38
mq/handlers.go

@@ -29,14 +29,14 @@ func Ping(client mqtt.Client, msg mqtt.Message) {
 		}
 		node, err := logic.GetNodeByID(id)
 		if err != nil {
-			logger.Log(0, "mq-ping error getting node: ", err.Error())
+			logger.Log(3, "mq-ping error getting node: ", err.Error())
 			record, err := database.FetchRecord(database.NODES_TABLE_NAME, id)
 			if err != nil {
-				logger.Log(0, "error reading database ", err.Error())
+				logger.Log(3, "error reading database ", err.Error())
 				return
 			}
-			logger.Log(0, "record from database")
-			logger.Log(0, record)
+			logger.Log(3, "record from database")
+			logger.Log(3, record)
 			return
 		}
 		decrypted, decryptErr := decryptMsg(&node, msg.Payload())
@@ -141,11 +141,11 @@ func UpdateHost(client mqtt.Client, msg mqtt.Message) {
 			logger.Log(1, "error unmarshaling payload ", err.Error())
 			return
 		}
-		logger.Log(0, "recieved host update for host: ", id)
+		logger.Log(3, fmt.Sprintf("recieved host update: %s\n", hostUpdate.Host.ID.String()))
 		var sendPeerUpdate bool
 		switch hostUpdate.Action {
 		case models.UpdateHost:
-			sendPeerUpdate = updateHostFromClient(&hostUpdate.Host, currentHost)
+			sendPeerUpdate = logic.UpdateHostFromClient(&hostUpdate.Host, currentHost)
 			err := logic.UpsertHost(currentHost)
 			if err != nil {
 				logger.Log(0, "failed to update host: ", currentHost.ID.String(), err.Error())
@@ -168,6 +168,12 @@ func UpdateHost(client mqtt.Client, msg mqtt.Message) {
 				logger.Log(0, "failed to pulish peer update: ", err.Error())
 			}
 		}
+		if sendPeerUpdate {
+			err := PublishPeerUpdate()
+			if err != nil {
+				logger.Log(0, "failed to pulish peer update: ", err.Error())
+			}
+		}
 		// if servercfg.Is_EE && ifaceDelta {
 		// 	if err = logic.EnterpriseResetAllPeersFailovers(currentHost.ID.String(), currentHost.Network); err != nil {
 		// 		logger.Log(1, "failed to reset failover list during node update", currentHost.ID.String(), currentHost.Network)
@@ -177,37 +183,6 @@ func UpdateHost(client mqtt.Client, msg mqtt.Message) {
 	}(msg)
 }
 
-// used for updating host on server with update recieved from client
-func updateHostFromClient(newHost, currHost *models.Host) (sendPeerUpdate bool) {
-
-	if newHost.ListenPort != 0 && currHost.ListenPort != newHost.ListenPort {
-		currHost.ListenPort = newHost.ListenPort
-		sendPeerUpdate = true
-	}
-	if newHost.ProxyListenPort != 0 && currHost.ProxyListenPort != newHost.ProxyListenPort {
-		currHost.ProxyListenPort = newHost.ProxyListenPort
-		sendPeerUpdate = true
-	}
-	if newHost.PublicListenPort != 0 && currHost.PublicListenPort != newHost.PublicListenPort {
-		currHost.PublicListenPort = newHost.PublicListenPort
-		sendPeerUpdate = true
-	}
-	if currHost.ProxyEnabled != newHost.ProxyEnabled {
-		currHost.ProxyEnabled = newHost.ProxyEnabled
-		sendPeerUpdate = true
-	}
-	if currHost.EndpointIP.String() != newHost.EndpointIP.String() {
-		currHost.EndpointIP = newHost.EndpointIP
-		sendPeerUpdate = true
-	}
-	currHost.DaemonInstalled = newHost.DaemonInstalled
-	currHost.Debug = newHost.Debug
-	currHost.Verbosity = newHost.Verbosity
-	currHost.Version = newHost.Version
-	currHost.Name = newHost.Name
-	return
-}
-
 // UpdateMetrics  message Handler -- handles updates from client nodes for metrics
 func UpdateMetrics(client mqtt.Client, msg mqtt.Message) {
 	if servercfg.Is_EE {
@@ -370,7 +345,7 @@ func updateNodeMetrics(currentNode *models.Node, newMetrics *models.Metrics) boo
 	for _, node := range nodes {
 		if !newMetrics.Connectivity[node.ID.String()].Connected &&
 			len(newMetrics.Connectivity[node.ID.String()].NodeName) > 0 &&
-			node.Connected == true &&
+			node.Connected &&
 			len(node.FailoverNode) > 0 &&
 			!node.Failover {
 			newMetrics.FailoverPeers[node.ID.String()] = node.FailoverNode.String()

+ 3 - 9
mq/publishers.go

@@ -6,12 +6,10 @@ import (
 	"fmt"
 	"time"
 
-	proxy_models "github.com/gravitl/netclient/nmproxy/models"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/servercfg"
-	"github.com/gravitl/netmaker/serverctl"
 )
 
 // PublishPeerUpdate --- determines and publishes a peer update to all the hosts
@@ -26,6 +24,7 @@ func PublishPeerUpdate() error {
 		return err
 	}
 	for _, host := range hosts {
+		host := host
 		err = PublishSingleHostUpdate(&host)
 		if err != nil {
 			logger.Log(1, "failed to publish peer update to host", host.ID.String(), ": ", err.Error())
@@ -46,7 +45,7 @@ func PublishSingleHostUpdate(host *models.Host) error {
 		if err != nil {
 			return err
 		}
-		proxyUpdate.Action = proxy_models.ProxyUpdate
+		proxyUpdate.Action = models.ProxyUpdate
 		peerUpdate.ProxyUpdate = proxyUpdate
 	}
 
@@ -123,13 +122,7 @@ func sendPeers() {
 	var force bool
 	peer_force_send++
 	if peer_force_send == 5 {
-
-		// run iptables update to ensure gateways work correctly and mq is forwarded if containerized
-		if servercfg.ManageIPTables() != "off" {
-			serverctl.InitIPTables(false)
-		}
 		servercfg.SetHost()
-
 		force = true
 		peer_force_send = 0
 		err := logic.TimerCheckpoint() // run telemetry & log dumps if 24 hours has passed..
@@ -142,6 +135,7 @@ func sendPeers() {
 
 	for _, host := range hosts {
 		if force {
+			host := host
 			logger.Log(2, "sending scheduled peer update (5 min)")
 			err = PublishSingleHostUpdate(&host)
 			if err != nil {

+ 0 - 2
netclient/ncutils/iface.go

@@ -23,8 +23,6 @@ func IfaceDelta(currentNode *models.LegacyNode, newNode *models.LegacyNode) bool
 		newNode.PersistentKeepalive != currentNode.PersistentKeepalive ||
 		newNode.DNSOn != currentNode.DNSOn ||
 		newNode.Connected != currentNode.Connected ||
-		newNode.PostUp != currentNode.PostUp ||
-		newNode.PostDown != currentNode.PostDown ||
 		len(newNode.AllowedIPs) != len(currentNode.AllowedIPs) {
 		return true
 	}

BIN
nm-proxy/bin/proxy.linux


+ 0 - 45
nm-proxy/common/common.go

@@ -1,45 +0,0 @@
-package common
-
-import (
-	"log"
-	"os/exec"
-	"strings"
-
-	"github.com/gravitl/netmaker/nm-proxy/models"
-)
-
-var IsHostNetwork bool
-var IsRelay bool
-var IsIngressGateway bool
-var IsRelayed bool
-var IsServer bool
-var InterfaceName string
-var BehindNAT bool
-
-var WgIfaceMap = models.WgIfaceConf{
-	Iface:   nil,
-	PeerMap: make(map[string]*models.Conn),
-}
-
-var PeerKeyHashMap = make(map[string]models.RemotePeer)
-
-//var WgIfaceKeyMap = make(map[string]models.RemotePeer)
-
-var RelayPeerMap = make(map[string]map[string]models.RemotePeer)
-
-var ExtClientsWaitTh = make(map[string]models.ExtClientPeer)
-
-var ExtSourceIpMap = make(map[string]models.RemotePeer)
-
-// RunCmd - runs a local command
-func RunCmd(command string, printerr bool) (string, error) {
-	args := strings.Fields(command)
-	cmd := exec.Command(args[0], args[1:]...)
-	cmd.Wait()
-	out, err := cmd.CombinedOutput()
-	if err != nil && printerr {
-		log.Println("error running command: ", command)
-		log.Println(strings.TrimSuffix(string(out), "\n"))
-	}
-	return string(out), err
-}

+ 0 - 22
nm-proxy/common/functions.go

@@ -1,22 +0,0 @@
-package common
-
-import (
-	"github.com/gravitl/netmaker/nm-proxy/models"
-	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
-)
-
-func GetPeer(peerKey wgtypes.Key) (*models.Conn, bool) {
-	var peerInfo *models.Conn
-	var found bool
-	peerInfo, found = WgIfaceMap.PeerMap[peerKey.String()]
-	peerInfo.Mutex.RLock()
-	defer peerInfo.Mutex.RUnlock()
-	return peerInfo, found
-
-}
-
-func UpdatePeer(peer *models.Conn) {
-	peer.Mutex.Lock()
-	defer peer.Mutex.Unlock()
-	WgIfaceMap.PeerMap[peer.Key.String()] = peer
-}

+ 0 - 424
nm-proxy/manager/manager.go

@@ -1,424 +0,0 @@
-package manager
-
-import (
-	"context"
-	"crypto/md5"
-	"errors"
-	"fmt"
-	"log"
-	"net"
-	"reflect"
-	"runtime"
-
-	"github.com/gravitl/netmaker/nm-proxy/common"
-	"github.com/gravitl/netmaker/nm-proxy/models"
-	peerpkg "github.com/gravitl/netmaker/nm-proxy/peer"
-	"github.com/gravitl/netmaker/nm-proxy/wg"
-	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
-)
-
-/*
-TODO:-
-	1. ON Ingress node
-		--> for attached ext clients
-			-> start sniffer (will recieve pkts from ext clients (add ebf filter to listen on only ext traffic) if not intended to the interface forward it.)
-			-> start remote conn after endpoint is updated
-		-->
-*/
-var sent bool
-
-type ProxyAction string
-
-type ManagerPayload struct {
-	InterfaceName   string                 `json:"interface_name"`
-	WgAddr          string                 `json:"wg_addr"`
-	Peers           []wgtypes.PeerConfig   `json:"peers"`
-	PeerMap         map[string]PeerConf    `json:"peer_map"`
-	IsRelayed       bool                   `json:"is_relayed"`
-	IsIngress       bool                   `json:"is_ingress"`
-	RelayedTo       *net.UDPAddr           `json:"relayed_to"`
-	IsRelay         bool                   `json:"is_relay"`
-	RelayedPeerConf map[string]RelayedConf `json:"relayed_conf"`
-}
-
-type RelayedConf struct {
-	RelayedPeerEndpoint *net.UDPAddr         `json:"relayed_peer_endpoint"`
-	RelayedPeerPubKey   string               `json:"relayed_peer_pub_key"`
-	Peers               []wgtypes.PeerConfig `json:"relayed_peers"`
-}
-
-type PeerConf struct {
-	IsExtClient            bool         `json:"is_ext_client"`
-	Address                string       `json:"address"`
-	IsAttachedExtClient    bool         `json:"is_attached_ext_client"`
-	IngressGatewayEndPoint *net.UDPAddr `json:"ingress_gateway_endpoint"`
-	IsRelayed              bool         `json:"is_relayed"`
-	RelayedTo              *net.UDPAddr `json:"relayed_to"`
-	Proxy                  bool         `json:"proxy"`
-}
-
-const (
-	AddInterface    ProxyAction = "ADD_INTERFACE"
-	DeleteInterface ProxyAction = "DELETE_INTERFACE"
-)
-
-type ManagerAction struct {
-	Action  ProxyAction
-	Payload ManagerPayload
-}
-
-func StartProxyManager(manageChan chan *ManagerAction) {
-	for {
-
-		select {
-		case mI := <-manageChan:
-			log.Printf("-------> PROXY-MANAGER: %+v\n", mI)
-			switch mI.Action {
-			case AddInterface:
-
-				mI.SetIngressGateway()
-				err := mI.AddInterfaceToProxy()
-				if err != nil {
-					log.Printf("failed to add interface: [%s] to proxy: %v\n  ", mI.Payload.InterfaceName, err)
-				}
-			case DeleteInterface:
-				mI.DeleteInterface()
-			}
-
-		}
-	}
-}
-
-func (m *ManagerAction) DeleteInterface() {
-	var err error
-	if runtime.GOOS == "darwin" {
-		m.Payload.InterfaceName, err = wg.GetRealIface(m.Payload.InterfaceName)
-		if err != nil {
-			log.Println("failed to get real iface: ", err)
-			return
-		}
-	}
-	if common.WgIfaceMap.Iface.Name == m.Payload.InterfaceName {
-		cleanUpInterface()
-	}
-
-}
-
-func (m *ManagerAction) RelayUpdate() {
-	common.IsRelay = m.Payload.IsRelay
-}
-
-func (m *ManagerAction) SetIngressGateway() {
-	common.IsIngressGateway = m.Payload.IsIngress
-
-}
-
-func (m *ManagerAction) RelayPeers() {
-	common.IsRelay = true
-	for relayedNodePubKey, relayedNodeConf := range m.Payload.RelayedPeerConf {
-		relayedNodePubKeyHash := fmt.Sprintf("%x", md5.Sum([]byte(relayedNodePubKey)))
-		if _, ok := common.RelayPeerMap[relayedNodePubKeyHash]; !ok {
-			common.RelayPeerMap[relayedNodePubKeyHash] = make(map[string]models.RemotePeer)
-		}
-		for _, peer := range relayedNodeConf.Peers {
-			if peer.Endpoint != nil {
-				peer.Endpoint.Port = models.NmProxyPort
-				remotePeerKeyHash := fmt.Sprintf("%x", md5.Sum([]byte(peer.PublicKey.String())))
-				common.RelayPeerMap[relayedNodePubKeyHash][remotePeerKeyHash] = models.RemotePeer{
-					Endpoint: peer.Endpoint,
-				}
-			}
-
-		}
-		relayedNodeConf.RelayedPeerEndpoint.Port = models.NmProxyPort
-		common.RelayPeerMap[relayedNodePubKeyHash][relayedNodePubKeyHash] = models.RemotePeer{
-			Endpoint: relayedNodeConf.RelayedPeerEndpoint,
-		}
-
-	}
-}
-
-func cleanUpInterface() {
-	log.Println("########------------>  CLEANING UP: ", common.WgIfaceMap.Iface.Name)
-	for _, peerI := range common.WgIfaceMap.PeerMap {
-		peerI.Mutex.Lock()
-		peerI.StopConn()
-		peerI.Mutex.Unlock()
-		delete(common.WgIfaceMap.PeerMap, peerI.Key.String())
-	}
-	common.WgIfaceMap.PeerMap = make(map[string]*models.Conn)
-}
-
-func (m *ManagerAction) processPayload() (*wg.WGIface, error) {
-	var err error
-	var wgIface *wg.WGIface
-	if m.Payload.InterfaceName == "" {
-		return nil, errors.New("interface cannot be empty")
-	}
-	if len(m.Payload.Peers) == 0 {
-		return nil, errors.New("no peers to add")
-	}
-
-	if runtime.GOOS == "darwin" {
-		m.Payload.InterfaceName, err = wg.GetRealIface(m.Payload.InterfaceName)
-		if err != nil {
-			log.Println("failed to get real iface: ", err)
-		}
-	}
-	common.InterfaceName = m.Payload.InterfaceName
-	wgIface, err = wg.NewWGIFace(m.Payload.InterfaceName, "127.0.0.1/32", wg.DefaultMTU)
-	if err != nil {
-		log.Println("Failed init new interface: ", err)
-		return nil, err
-	}
-
-	if common.WgIfaceMap.Iface == nil {
-		for i := len(m.Payload.Peers) - 1; i >= 0; i-- {
-			if !m.Payload.PeerMap[m.Payload.Peers[i].PublicKey.String()].Proxy {
-				log.Println("-----------> skipping peer, proxy is off: ", m.Payload.Peers[i].PublicKey)
-				if err := wgIface.Update(m.Payload.Peers[i], false); err != nil {
-					log.Println("falied to update peer: ", err)
-				}
-				m.Payload.Peers = append(m.Payload.Peers[:i], m.Payload.Peers[i+1:]...)
-				continue
-			}
-		}
-		common.WgIfaceMap.Iface = wgIface.Device
-		common.WgIfaceMap.IfaceKeyHash = fmt.Sprintf("%x", md5.Sum([]byte(wgIface.Device.PublicKey.String())))
-		return wgIface, nil
-	}
-	wgProxyConf := common.WgIfaceMap
-	if m.Payload.IsRelay {
-		m.RelayPeers()
-	}
-	common.IsRelay = m.Payload.IsRelay
-	// check if node is getting relayed
-	if common.IsRelayed != m.Payload.IsRelayed {
-		common.IsRelayed = m.Payload.IsRelayed
-		cleanUpInterface()
-		return wgIface, nil
-	}
-
-	// sync map with wg device config
-	// check if listen port has changed
-	if wgIface.Device.ListenPort != wgProxyConf.Iface.ListenPort {
-		// reset proxy for this interface
-		cleanUpInterface()
-		return wgIface, nil
-	}
-	// check device conf different from proxy
-	wgProxyConf.Iface = wgIface.Device
-	// sync peer map with new update
-	for _, currPeerI := range wgProxyConf.Iface.Peers {
-		if _, ok := m.Payload.PeerMap[currPeerI.PublicKey.String()]; !ok {
-			if val, ok := wgProxyConf.PeerMap[currPeerI.PublicKey.String()]; ok {
-				val.Mutex.Lock()
-				if val.IsAttachedExtClient {
-					log.Println("------> Deleting ExtClient Watch Thread: ", currPeerI.PublicKey.String())
-					if val, ok := common.ExtClientsWaitTh[currPeerI.PublicKey.String()]; ok {
-						val.CancelFunc()
-						delete(common.ExtClientsWaitTh, currPeerI.PublicKey.String())
-					}
-					log.Println("-----> Deleting Ext Client from Src Ip Map: ", currPeerI.PublicKey.String())
-					delete(common.ExtSourceIpMap, val.Config.PeerConf.Endpoint.String())
-				}
-				val.StopConn()
-				val.Mutex.Unlock()
-				delete(wgProxyConf.PeerMap, currPeerI.PublicKey.String())
-			}
-
-			// delete peer from interface
-			log.Println("CurrPeer Not Found, Deleting Peer from Interface: ", currPeerI.PublicKey.String())
-			if err := wgIface.RemovePeer(currPeerI.PublicKey.String()); err != nil {
-				log.Println("failed to remove peer: ", currPeerI.PublicKey.String(), err)
-			}
-
-			delete(common.PeerKeyHashMap, fmt.Sprintf("%x", md5.Sum([]byte(currPeerI.PublicKey.String()))))
-
-		}
-	}
-	for i := len(m.Payload.Peers) - 1; i >= 0; i-- {
-
-		if currentPeer, ok := wgProxyConf.PeerMap[m.Payload.Peers[i].PublicKey.String()]; ok {
-			currentPeer.Mutex.Lock()
-			if currentPeer.IsAttachedExtClient {
-				m.Payload.Peers = append(m.Payload.Peers[:i], m.Payload.Peers[i+1:]...)
-				continue
-			}
-			// check if proxy is off for the peer
-			if !m.Payload.PeerMap[m.Payload.Peers[i].PublicKey.String()].Proxy {
-
-				// cleanup proxy connections for the peer
-				currentPeer.StopConn()
-				delete(wgProxyConf.PeerMap, currentPeer.Key.String())
-				// update the peer with actual endpoint
-				if err := wgIface.Update(m.Payload.Peers[i], false); err != nil {
-					log.Println("falied to update peer: ", err)
-				}
-				m.Payload.Peers = append(m.Payload.Peers[:i], m.Payload.Peers[i+1:]...)
-				continue
-
-			}
-			// check if peer is not connected to proxy
-			devPeer, err := wg.GetPeer(m.Payload.InterfaceName, currentPeer.Key.String())
-			if err == nil {
-				log.Printf("---------> COMAPRING ENDPOINT: DEV: %s, Proxy: %s", devPeer.Endpoint.String(), currentPeer.Config.LocalConnAddr.String())
-				if devPeer.Endpoint.String() != currentPeer.Config.LocalConnAddr.String() {
-					log.Println("---------> endpoint is not set to proxy: ", currentPeer.Key)
-					currentPeer.StopConn()
-					delete(wgProxyConf.PeerMap, currentPeer.Key.String())
-					continue
-				}
-			}
-			//check if peer is being relayed
-			if currentPeer.IsRelayed != m.Payload.PeerMap[m.Payload.Peers[i].PublicKey.String()].IsRelayed {
-				log.Println("---------> peer relay status has been changed: ", currentPeer.Key)
-				currentPeer.StopConn()
-				delete(wgProxyConf.PeerMap, currentPeer.Key.String())
-				continue
-			}
-			// check if relay endpoint has been changed
-			if currentPeer.RelayedEndpoint != nil &&
-				m.Payload.PeerMap[m.Payload.Peers[i].PublicKey.String()].RelayedTo != nil &&
-				currentPeer.RelayedEndpoint.String() != m.Payload.PeerMap[m.Payload.Peers[i].PublicKey.String()].RelayedTo.String() {
-				log.Println("---------> peer relay endpoint has been changed: ", currentPeer.Key)
-				currentPeer.StopConn()
-				delete(wgProxyConf.PeerMap, currentPeer.Key.String())
-				continue
-			}
-			if !reflect.DeepEqual(m.Payload.Peers[i], *currentPeer.Config.PeerConf) {
-				if currentPeer.Config.RemoteConnAddr.IP.String() != m.Payload.Peers[i].Endpoint.IP.String() {
-					log.Println("----------> Resetting proxy for Peer: ", currentPeer.Key, m.Payload.InterfaceName)
-					currentPeer.StopConn()
-					currentPeer.Mutex.Unlock()
-					delete(wgProxyConf.PeerMap, currentPeer.Key.String())
-					continue
-				} else {
-
-					log.Println("----->##### Updating Peer on Interface: ", m.Payload.InterfaceName, currentPeer.Key)
-					updatePeerConf := m.Payload.Peers[i]
-					localUdpAddr, err := net.ResolveUDPAddr("udp", currentPeer.Config.LocalConnAddr.String())
-					if err == nil {
-						updatePeerConf.Endpoint = localUdpAddr
-					}
-					if err := wgIface.Update(updatePeerConf, true); err != nil {
-						log.Println("failed to update peer: ", currentPeer.Key, err)
-					}
-					currentPeer.Config.PeerConf = &m.Payload.Peers[i]
-					wgProxyConf.PeerMap[currentPeer.Key.String()] = currentPeer
-					// delete the peer from the list
-					log.Println("-----------> deleting peer from list: ", m.Payload.Peers[i].PublicKey)
-					m.Payload.Peers = append(m.Payload.Peers[:i], m.Payload.Peers[i+1:]...)
-
-				}
-
-			} else {
-				// delete the peer from the list
-				log.Println("-----------> No updates observed so deleting peer: ", m.Payload.Peers[i].PublicKey)
-				m.Payload.Peers = append(m.Payload.Peers[:i], m.Payload.Peers[i+1:]...)
-			}
-			currentPeer.Mutex.Unlock()
-
-		} else if !m.Payload.PeerMap[m.Payload.Peers[i].PublicKey.String()].Proxy && !m.Payload.PeerMap[m.Payload.Peers[i].PublicKey.String()].IsAttachedExtClient {
-			log.Println("-----------> skipping peer, proxy is off: ", m.Payload.Peers[i].PublicKey)
-			if err := wgIface.Update(m.Payload.Peers[i], false); err != nil {
-				log.Println("falied to update peer: ", err)
-			}
-			m.Payload.Peers = append(m.Payload.Peers[:i], m.Payload.Peers[i+1:]...)
-		}
-	}
-
-	// sync dev peers with new update
-
-	common.WgIfaceMap = wgProxyConf
-
-	log.Println("CLEANED UP..........")
-	return wgIface, nil
-}
-
-func (m *ManagerAction) AddInterfaceToProxy() error {
-	var err error
-
-	wgInterface, err := m.processPayload()
-	if err != nil {
-		return err
-	}
-
-	log.Printf("wg: %+v\n", wgInterface)
-	for _, peerI := range m.Payload.Peers {
-
-		peerConf := m.Payload.PeerMap[peerI.PublicKey.String()]
-		if peerI.Endpoint == nil && !(peerConf.IsAttachedExtClient || peerConf.IsExtClient) {
-			log.Println("Endpoint nil for peer: ", peerI.PublicKey.String())
-			continue
-		}
-
-		if peerConf.IsExtClient && !peerConf.IsAttachedExtClient {
-			peerI.Endpoint = peerConf.IngressGatewayEndPoint
-		}
-
-		var isRelayed bool
-		var relayedTo *net.UDPAddr
-		if m.Payload.IsRelayed {
-			isRelayed = true
-			relayedTo = m.Payload.RelayedTo
-		} else {
-
-			isRelayed = peerConf.IsRelayed
-			relayedTo = peerConf.RelayedTo
-
-		}
-		if peerConf.IsAttachedExtClient {
-			log.Println("Extclient Thread...")
-			go func(wgInterface *wg.WGIface, peer *wgtypes.PeerConfig,
-				isRelayed bool, relayTo *net.UDPAddr, peerConf PeerConf, ingGwAddr string) {
-				addExtClient := false
-				commChan := make(chan *net.UDPAddr, 100)
-				ctx, cancel := context.WithCancel(context.Background())
-				common.ExtClientsWaitTh[peerI.PublicKey.String()] = models.ExtClientPeer{
-					CancelFunc: cancel,
-					CommChan:   commChan,
-				}
-				defer func() {
-					if addExtClient {
-						log.Println("GOT ENDPOINT for Extclient adding peer...")
-
-						common.ExtSourceIpMap[peer.Endpoint.String()] = models.RemotePeer{
-							Interface:           wgInterface.Name,
-							PeerKey:             peer.PublicKey.String(),
-							IsExtClient:         peerConf.IsExtClient,
-							IsAttachedExtClient: peerConf.IsAttachedExtClient,
-							Endpoint:            peer.Endpoint,
-						}
-
-						peerpkg.AddNewPeer(wgInterface, peer, peerConf.Address, isRelayed,
-							peerConf.IsExtClient, peerConf.IsAttachedExtClient, relayedTo)
-
-					}
-					log.Println("Exiting extclient watch Thread for: ", peer.PublicKey.String())
-				}()
-				for {
-					select {
-					case <-ctx.Done():
-						return
-					case endpoint := <-commChan:
-						if endpoint != nil {
-							addExtClient = true
-							peer.Endpoint = endpoint
-							delete(common.ExtClientsWaitTh, peer.PublicKey.String())
-							return
-						}
-					}
-
-				}
-
-			}(wgInterface, &peerI, isRelayed, relayedTo, peerConf, m.Payload.WgAddr)
-			continue
-		}
-
-		peerpkg.AddNewPeer(wgInterface, &peerI, peerConf.Address, isRelayed,
-			peerConf.IsExtClient, peerConf.IsAttachedExtClient, relayedTo)
-
-	}
-	return nil
-}

+ 0 - 56
nm-proxy/metrics/metrics.go

@@ -1,56 +0,0 @@
-package metrics
-
-import (
-	"encoding/json"
-	"os"
-	"sync"
-	"time"
-)
-
-/*
-1. Create metrics packet--> packet with identifier to track latency, errors.
-
-*/
-
-type Metric struct {
-	LastRecordedLatency uint64
-	ConnectionStatus    bool
-	TrafficSent         float64
-	TrafficRecieved     float64
-}
-
-type MetricsPayload struct {
-	MetricType MetricsUpdateType
-	Value      interface{}
-}
-
-type MetricsUpdateType uint32
-
-const (
-	LatencyUpdate         MetricsUpdateType = 1
-	TrafficSentUpdate     MetricsUpdateType = 2
-	TrafficRecievedUpdate MetricsUpdateType = 3
-)
-
-var MetricsMapLock = &sync.RWMutex{}
-
-var MetricsMap = make(map[string]Metric)
-
-func init() {
-	go func() {
-		for {
-			time.Sleep(1 * time.Minute)
-			PrintMetrics()
-		}
-	}()
-}
-
-func PrintMetrics() {
-
-	data, err := json.MarshalIndent(MetricsMap, "", " ")
-	if err != nil {
-		return
-	}
-	os.WriteFile("/tmp/metrics.json", data, 0755)
-
-}

+ 0 - 65
nm-proxy/models/models.go

@@ -1,65 +0,0 @@
-package models
-
-import (
-	"context"
-	"net"
-	"sync"
-	"time"
-
-	"github.com/gravitl/netmaker/nm-proxy/wg"
-	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
-)
-
-const (
-	NmProxyPort = 51722
-	DefaultCIDR = "127.0.0.1/8"
-)
-
-type ProxyConfig struct {
-	RemoteKey           wgtypes.Key
-	LocalKey            wgtypes.Key
-	WgInterface         *wg.WGIface
-	IsExtClient         bool
-	PersistentKeepalive *time.Duration
-	RecieverChan        chan []byte
-	PeerConf            *wgtypes.PeerConfig
-	PeerEndpoint        *net.UDPAddr
-	RemoteConnAddr      *net.UDPAddr
-	LocalConnAddr       *net.UDPAddr
-}
-
-// Conn is a peer Connection configuration
-type Conn struct {
-
-	// Key is a public key of a remote peer
-	Key                 wgtypes.Key
-	IsExtClient         bool
-	IsRelayed           bool
-	RelayedEndpoint     *net.UDPAddr
-	IsAttachedExtClient bool
-	Config              ProxyConfig
-	StopConn            func()
-	ResetConn           func()
-	LocalConn           net.Conn
-	Mutex               *sync.RWMutex
-}
-
-type RemotePeer struct {
-	PeerKey             string
-	Interface           string
-	Endpoint            *net.UDPAddr
-	IsExtClient         bool
-	IsAttachedExtClient bool
-	LocalConn           net.Conn
-}
-
-type ExtClientPeer struct {
-	CancelFunc context.CancelFunc
-	CommChan   chan *net.UDPAddr
-}
-
-type WgIfaceConf struct {
-	Iface        *wgtypes.Device
-	IfaceKeyHash string
-	PeerMap      map[string]*Conn
-}

+ 0 - 47
nm-proxy/nm-proxy.go

@@ -1,47 +0,0 @@
-package nmproxy
-
-import (
-	"context"
-	"log"
-	"net"
-	"os"
-
-	"github.com/gravitl/netmaker/nm-proxy/common"
-	"github.com/gravitl/netmaker/nm-proxy/manager"
-	"github.com/gravitl/netmaker/nm-proxy/server"
-	"github.com/gravitl/netmaker/nm-proxy/stun"
-)
-
-/*
-	TODO:
-		1. Mutex locks for maps
-		2. CRUD funcs on Maps
-		3. Comments
-*/
-
-func Start(ctx context.Context, mgmChan chan *manager.ManagerAction, apiServerAddr string) {
-	log.Println("Starting Proxy...")
-	common.IsHostNetwork = (os.Getenv("HOST_NETWORK") == "" || os.Getenv("HOST_NETWORK") == "on")
-	hInfo := stun.GetHostInfo(apiServerAddr)
-	stun.Host = hInfo
-	log.Printf("HOSTINFO: %+v", hInfo)
-	if IsPublicIP(hInfo.PrivIp) {
-		log.Println("Host is public facing!!!")
-	}
-	// start the netclient proxy server
-	err := server.NmProxyServer.CreateProxyServer(0, 0, hInfo.PrivIp.String())
-	if err != nil {
-		log.Fatal("failed to create proxy: ", err)
-	}
-	go manager.StartProxyManager(mgmChan)
-	server.NmProxyServer.Listen(ctx)
-
-}
-
-// IsPublicIP indicates whether IP is public or not.
-func IsPublicIP(ip net.IP) bool {
-	if ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() || ip.IsPrivate() {
-		return false
-	}
-	return true
-}

+ 0 - 174
nm-proxy/packet/packet.go

@@ -1,174 +0,0 @@
-package packet
-
-import (
-	"bytes"
-	"crypto/md5"
-	"encoding/base64"
-	"encoding/binary"
-	"errors"
-	"fmt"
-	"log"
-	"net"
-	"time"
-
-	"github.com/gravitl/netmaker/nm-proxy/common"
-	"golang.org/x/crypto/blake2s"
-	"golang.org/x/crypto/chacha20poly1305"
-	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
-)
-
-func ConsumeHandshakeInitiationMsg(initiator bool, buf []byte, src *net.UDPAddr, devicePubKey NoisePublicKey, devicePrivKey NoisePrivateKey) error {
-
-	var (
-		hash     [blake2s.Size]byte
-		chainKey [blake2s.Size]byte
-	)
-	var err error
-	var msg MessageInitiation
-	reader := bytes.NewReader(buf[:])
-	err = binary.Read(reader, binary.LittleEndian, &msg)
-	if err != nil {
-		log.Println("Failed to decode initiation message")
-		return err
-	}
-
-	if msg.Type != MessageInitiationType {
-		return errors.New("not handshake initiation message")
-	}
-	log.Println("-----> ConsumeHandshakeInitiationMsg, Intitator:  ", initiator)
-	mixHash(&hash, &InitialHash, devicePubKey[:])
-	mixHash(&hash, &hash, msg.Ephemeral[:])
-	mixKey(&chainKey, &InitialChainKey, msg.Ephemeral[:])
-
-	// decrypt static key
-	var peerPK NoisePublicKey
-	var key [chacha20poly1305.KeySize]byte
-	ss := sharedSecret(&devicePrivKey, msg.Ephemeral)
-	if isZero(ss[:]) {
-		return errors.New("no secret")
-	}
-	KDF2(&chainKey, &key, chainKey[:], ss[:])
-	aead, _ := chacha20poly1305.New(key[:])
-	_, err = aead.Open(peerPK[:0], ZeroNonce[:], msg.Static[:], hash[:])
-	if err != nil {
-		return err
-	}
-	log.Println("--------> Got HandShake from peer: ", base64.StdEncoding.EncodeToString(peerPK[:]), src)
-	if val, ok := common.ExtClientsWaitTh[base64.StdEncoding.EncodeToString(peerPK[:])]; ok {
-		val.CommChan <- src
-		time.Sleep(time.Second * 3)
-	}
-
-	setZero(hash[:])
-	setZero(chainKey[:])
-	return nil
-}
-
-func CreateProxyUpdatePacket(msg *ProxyUpdateMessage) ([]byte, error) {
-	var buff [MessageProxyUpdateSize]byte
-	writer := bytes.NewBuffer(buff[:0])
-	err := binary.Write(writer, binary.LittleEndian, msg)
-	if err != nil {
-		return nil, err
-	}
-	packet := writer.Bytes()
-	return packet, nil
-
-}
-
-func ConsumeProxyUpdateMsg(buf []byte) (*ProxyUpdateMessage, error) {
-	var msg ProxyUpdateMessage
-	reader := bytes.NewReader(buf[:])
-	err := binary.Read(reader, binary.LittleEndian, &msg)
-	if err != nil {
-		log.Println("Failed to decode proxy update message")
-		return nil, err
-	}
-
-	if msg.Type != MessageProxyUpdateType {
-		return nil, errors.New("not proxy update message")
-	}
-	return &msg, nil
-}
-
-func CreateMetricPacket(id uint32, sender, reciever wgtypes.Key) ([]byte, error) {
-	msg := MetricMessage{
-		Type:      MessageMetricsType,
-		ID:        id,
-		Sender:    sender,
-		Reciever:  reciever,
-		TimeStamp: time.Now().UnixMilli(),
-	}
-	log.Printf("----------> $$$$$$ CREATED PACKET: %+v\n", msg)
-	var buff [MessageMetricSize]byte
-	writer := bytes.NewBuffer(buff[:0])
-	err := binary.Write(writer, binary.LittleEndian, msg)
-	if err != nil {
-		return nil, err
-	}
-	packet := writer.Bytes()
-	return packet, nil
-}
-
-func ConsumeMetricPacket(buf []byte) (*MetricMessage, error) {
-	var msg MetricMessage
-	var err error
-	reader := bytes.NewReader(buf[:])
-	err = binary.Read(reader, binary.LittleEndian, &msg)
-	if err != nil {
-		log.Println("Failed to decode metric message")
-		return nil, err
-	}
-
-	if msg.Type != MessageMetricsType {
-		return nil, errors.New("not  metric message")
-	}
-	return &msg, nil
-}
-
-func ProcessPacketBeforeSending(buf []byte, n int, srckey, dstKey string) ([]byte, int, string, string) {
-
-	srcKeymd5 := md5.Sum([]byte(srckey))
-	dstKeymd5 := md5.Sum([]byte(dstKey))
-	m := ProxyMessage{
-		Type:     MessageProxyType,
-		Sender:   srcKeymd5,
-		Reciever: dstKeymd5,
-	}
-	var msgBuffer [MessageProxySize]byte
-	writer := bytes.NewBuffer(msgBuffer[:0])
-	err := binary.Write(writer, binary.LittleEndian, m)
-	if err != nil {
-		log.Println(err)
-	}
-	if n > len(buf)-MessageProxySize {
-		buf = append(buf, msgBuffer[:]...)
-
-	} else {
-		copy(buf[n:n+MessageProxySize], msgBuffer[:])
-	}
-	n += MessageProxySize
-
-	return buf, n, fmt.Sprintf("%x", srcKeymd5), fmt.Sprintf("%x", dstKeymd5)
-}
-
-func ExtractInfo(buffer []byte, n int) (int, string, string, error) {
-	data := buffer[:n]
-	if len(data) < MessageProxySize {
-		return n, "", "", errors.New("proxy message not found")
-	}
-	var msg ProxyMessage
-	var err error
-	reader := bytes.NewReader(buffer[n-MessageProxySize:])
-	err = binary.Read(reader, binary.LittleEndian, &msg)
-	if err != nil {
-		log.Println("Failed to decode proxy message")
-		return n, "", "", err
-	}
-
-	if msg.Type != MessageProxyType {
-		return n, "", "", errors.New("not a proxy message")
-	}
-	n -= MessageProxySize
-	return n, fmt.Sprintf("%x", msg.Sender), fmt.Sprintf("%x", msg.Reciever), nil
-}

+ 0 - 52
nm-proxy/packet/packet_helper.go

@@ -1,52 +0,0 @@
-package packet
-
-import (
-	"golang.org/x/crypto/blake2s"
-	"golang.org/x/crypto/chacha20poly1305"
-	"golang.org/x/crypto/poly1305"
-	"golang.zx2c4.com/wireguard/tai64n"
-	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
-)
-
-var (
-	InitialChainKey [blake2s.Size]byte
-	InitialHash     [blake2s.Size]byte
-	ZeroNonce       [chacha20poly1305.NonceSize]byte
-)
-
-func init() {
-	InitialChainKey = blake2s.Sum256([]byte(NoiseConstruction))
-	mixHash(&InitialHash, &InitialChainKey, []byte(WGIdentifier))
-}
-
-type MessageInitiation struct {
-	Type      MessageType
-	Sender    uint32
-	Ephemeral NoisePublicKey
-	Static    [NoisePublicKeySize + poly1305.TagSize]byte
-	Timestamp [tai64n.TimestampSize + poly1305.TagSize]byte
-	MAC1      [blake2s.Size128]byte
-	MAC2      [blake2s.Size128]byte
-}
-
-type MetricMessage struct {
-	Type      MessageType
-	ID        uint32
-	Sender    wgtypes.Key
-	Reciever  wgtypes.Key
-	TimeStamp int64
-}
-
-type ProxyMessage struct {
-	Type     MessageType
-	Sender   [16]byte
-	Reciever [16]byte
-}
-
-type ProxyUpdateMessage struct {
-	Type       MessageType
-	Action     ProxyActionType
-	Sender     wgtypes.Key
-	Reciever   wgtypes.Key
-	ListenPort uint32
-}

+ 0 - 113
nm-proxy/packet/utils.go

@@ -1,113 +0,0 @@
-package packet
-
-import (
-	"crypto/hmac"
-	"crypto/subtle"
-	"hash"
-
-	"github.com/gravitl/netmaker/nm-proxy/wg"
-	"golang.org/x/crypto/blake2s"
-	"golang.org/x/crypto/curve25519"
-)
-
-type MessageType uint32
-type ProxyActionType uint32
-
-const (
-	MessageInitiationType  MessageType = 1
-	MessageMetricsType     MessageType = 5
-	MessageProxyType       MessageType = 6
-	MessageProxyUpdateType MessageType = 7
-)
-
-const (
-	UpdateListenPort ProxyActionType = 1
-)
-const (
-	NoisePublicKeySize  = 32
-	NoisePrivateKeySize = 32
-
-	MessageMetricSize      = 148
-	MessageProxyUpdateSize = 148
-	MessageProxySize       = 36
-
-	NoiseConstruction = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"
-	WGIdentifier      = "WireGuard v1 zx2c4 [email protected]"
-	WGLabelMAC1       = "mac1----"
-	WGLabelCookie     = "cookie--"
-)
-
-func mixKey(dst, c *[blake2s.Size]byte, data []byte) {
-	KDF1(dst, c[:], data)
-}
-
-func mixHash(dst, h *[blake2s.Size]byte, data []byte) {
-	hash, _ := blake2s.New256(nil)
-	hash.Write(h[:])
-	hash.Write(data)
-	hash.Sum(dst[:0])
-	hash.Reset()
-}
-func HMAC1(sum *[blake2s.Size]byte, key, in0 []byte) {
-	mac := hmac.New(func() hash.Hash {
-		h, _ := blake2s.New256(nil)
-		return h
-	}, key)
-	mac.Write(in0)
-	mac.Sum(sum[:0])
-}
-
-func HMAC2(sum *[blake2s.Size]byte, key, in0, in1 []byte) {
-	mac := hmac.New(func() hash.Hash {
-		h, _ := blake2s.New256(nil)
-		return h
-	}, key)
-	mac.Write(in0)
-	mac.Write(in1)
-	mac.Sum(sum[:0])
-}
-
-func KDF1(t0 *[blake2s.Size]byte, key, input []byte) {
-	HMAC1(t0, key, input)
-	HMAC1(t0, t0[:], []byte{0x1})
-}
-
-func KDF2(t0, t1 *[blake2s.Size]byte, key, input []byte) {
-	var prk [blake2s.Size]byte
-	HMAC1(&prk, key, input)
-	HMAC1(t0, prk[:], []byte{0x1})
-	HMAC2(t1, prk[:], t0[:], []byte{0x2})
-	setZero(prk[:])
-}
-
-func setZero(arr []byte) {
-	for i := range arr {
-		arr[i] = 0
-	}
-}
-func isZero(val []byte) bool {
-	acc := 1
-	for _, b := range val {
-		acc &= subtle.ConstantTimeByteEq(b, 0)
-	}
-	return acc == 1
-}
-
-func GetDeviceKeys(ifaceName string) (NoisePrivateKey, NoisePublicKey, error) {
-	wgPrivKey := wg.GetWgIfacePrivKey(ifaceName)
-	wgPubKey := wg.GetWgIfacePubKey(ifaceName)
-
-	return wgPrivKey, wgPubKey, nil
-}
-
-type (
-	NoisePublicKey  [NoisePublicKeySize]byte
-	NoisePrivateKey [NoisePrivateKeySize]byte
-)
-
-func sharedSecret(sk *NoisePrivateKey, pk NoisePublicKey) (ss [NoisePublicKeySize]byte) {
-	apk := (*[NoisePublicKeySize]byte)(&pk)
-	ask := (*[NoisePrivateKeySize]byte)(sk)
-	curve25519.ScalarMult(&ss, ask, apk)
-	return ss
-}

+ 0 - 83
nm-proxy/peer/peer.go

@@ -1,83 +0,0 @@
-package peer
-
-import (
-	"crypto/md5"
-	"errors"
-	"fmt"
-	"log"
-	"net"
-	"sync"
-	"time"
-
-	"github.com/gravitl/netmaker/nm-proxy/common"
-	"github.com/gravitl/netmaker/nm-proxy/models"
-	"github.com/gravitl/netmaker/nm-proxy/proxy"
-	"github.com/gravitl/netmaker/nm-proxy/wg"
-	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
-)
-
-func AddNewPeer(wgInterface *wg.WGIface, peer *wgtypes.PeerConfig, peerAddr string,
-	isRelayed, isExtClient, isAttachedExtClient bool, relayTo *net.UDPAddr) error {
-	if peer.PersistentKeepaliveInterval == nil {
-		d := time.Second * 25
-		peer.PersistentKeepaliveInterval = &d
-	}
-	c := models.ProxyConfig{
-		LocalKey:            wgInterface.Device.PublicKey,
-		RemoteKey:           peer.PublicKey,
-		WgInterface:         wgInterface,
-		IsExtClient:         isExtClient,
-		PeerConf:            peer,
-		PersistentKeepalive: peer.PersistentKeepaliveInterval,
-		RecieverChan:        make(chan []byte, 1000),
-	}
-	p := proxy.NewProxy(c)
-	peerPort := models.NmProxyPort
-	if isExtClient && isAttachedExtClient {
-		peerPort = peer.Endpoint.Port
-
-	}
-	peerEndpointIP := peer.Endpoint.IP
-	if isRelayed {
-		//go server.NmProxyServer.KeepAlive(peer.Endpoint.IP.String(), common.NmProxyPort)
-		if relayTo == nil {
-			return errors.New("relay endpoint is nil")
-		}
-		peerEndpointIP = relayTo.IP
-	}
-	peerEndpoint, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", peerEndpointIP, peerPort))
-	if err != nil {
-		return err
-	}
-	p.Config.PeerEndpoint = peerEndpoint
-
-	log.Printf("Starting proxy for Peer: %s\n", peer.PublicKey.String())
-	err = p.Start()
-	if err != nil {
-		return err
-	}
-
-	connConf := models.Conn{
-		Mutex:               &sync.RWMutex{},
-		Key:                 peer.PublicKey,
-		IsRelayed:           isRelayed,
-		RelayedEndpoint:     relayTo,
-		IsAttachedExtClient: isAttachedExtClient,
-		Config:              p.Config,
-		StopConn:            p.Close,
-		ResetConn:           p.Reset,
-		LocalConn:           p.LocalConn,
-	}
-
-	common.WgIfaceMap.PeerMap[peer.PublicKey.String()] = &connConf
-
-	common.PeerKeyHashMap[fmt.Sprintf("%x", md5.Sum([]byte(peer.PublicKey.String())))] = models.RemotePeer{
-		Interface:           wgInterface.Name,
-		PeerKey:             peer.PublicKey.String(),
-		IsExtClient:         isExtClient,
-		Endpoint:            peerEndpoint,
-		IsAttachedExtClient: isAttachedExtClient,
-		LocalConn:           p.LocalConn,
-	}
-	return nil
-}

+ 0 - 266
nm-proxy/proxy/proxy.go

@@ -1,266 +0,0 @@
-package proxy
-
-import (
-	"context"
-	"errors"
-	"fmt"
-	"log"
-	"net"
-	"runtime"
-
-	"github.com/gravitl/netmaker/nm-proxy/common"
-	"github.com/gravitl/netmaker/nm-proxy/models"
-)
-
-// Proxy -  WireguardProxy proxies
-type Proxy struct {
-	Ctx        context.Context
-	Cancel     context.CancelFunc
-	Config     models.ProxyConfig
-	RemoteConn *net.UDPAddr
-	LocalConn  net.Conn
-}
-
-func (p *Proxy) Start() error {
-
-	var err error
-	p.RemoteConn = p.Config.PeerEndpoint
-	log.Printf("----> Established Remote Conn with RPeer: %s, ----> RAddr: %s", p.Config.RemoteKey.String(), p.RemoteConn.String())
-	addr, err := GetFreeIp(models.DefaultCIDR, p.Config.WgInterface.Port)
-	if err != nil {
-		log.Println("Failed to get freeIp: ", err)
-		return err
-	}
-	wgListenAddr, err := GetInterfaceListenAddr(p.Config.WgInterface.Port)
-	if err != nil {
-		log.Println("failed to get wg listen addr: ", err)
-		return err
-	}
-	if runtime.GOOS == "darwin" {
-		wgListenAddr.IP = net.ParseIP(addr)
-	}
-	p.LocalConn, err = net.DialUDP("udp", &net.UDPAddr{
-		IP:   net.ParseIP(addr),
-		Port: models.NmProxyPort,
-	}, wgListenAddr)
-	if err != nil {
-		log.Printf("failed dialing to local Wireguard port,Err: %v\n", err)
-		return err
-	}
-
-	log.Printf("Dialing to local Wireguard port %s --> %s\n", p.LocalConn.LocalAddr().String(), p.LocalConn.RemoteAddr().String())
-	err = p.updateEndpoint()
-	if err != nil {
-		log.Printf("error while updating Wireguard peer endpoint [%s] %v\n", p.Config.RemoteKey, err)
-		return err
-	}
-	localAddr, err := net.ResolveUDPAddr("udp", p.LocalConn.LocalAddr().String())
-	if err != nil {
-		log.Println("failed to resolve local addr: ", err)
-		return err
-	}
-	p.Config.LocalConnAddr = localAddr
-	p.Config.RemoteConnAddr = p.RemoteConn
-	go p.ProxyPeer()
-
-	return nil
-}
-
-func (p *Proxy) Close() {
-	log.Println("------> Closing Proxy for ", p.Config.RemoteKey.String())
-	p.Cancel()
-	p.LocalConn.Close()
-	if runtime.GOOS == "darwin" {
-		host, _, err := net.SplitHostPort(p.LocalConn.LocalAddr().String())
-		if err != nil {
-			log.Println("Failed to split host: ", p.LocalConn.LocalAddr().String(), err)
-			return
-		}
-
-		if host != "127.0.0.1" {
-			_, err = common.RunCmd(fmt.Sprintf("ifconfig lo0 -alias %s 255.255.255.255", host), true)
-			if err != nil {
-				log.Println("Failed to add alias: ", err)
-			}
-		}
-
-	}
-	close(p.Config.RecieverChan)
-}
-
-func GetInterfaceListenAddr(port int) (*net.UDPAddr, error) {
-	locallistenAddr := "127.0.0.1"
-	udpAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", locallistenAddr, port))
-	if err != nil {
-		return udpAddr, err
-	}
-	if !common.IsHostNetwork {
-		addrs, err := getBoardCastAddress()
-		if err != nil {
-			return udpAddr, err
-		}
-		for _, addr := range addrs {
-			if liAddr := addr.(*net.IPNet).IP; liAddr != nil {
-				udpAddr.IP = liAddr
-				break
-			}
-		}
-	}
-
-	return udpAddr, nil
-}
-
-func getBoardCastAddress() ([]net.Addr, error) {
-	localnets, err := net.Interfaces()
-	if err != nil {
-		return nil, err
-	}
-	var (
-		ief   net.Interface
-		addrs []net.Addr
-	)
-	for _, ief = range localnets {
-		if ief.Flags&net.FlagBroadcast != 0 && ief.Flags&net.FlagUp != 0 {
-			addrs, err = ief.Addrs()
-			if err == nil {
-				return addrs, nil
-			}
-
-		}
-	}
-	return nil, errors.New("couldn't obtain the broadcast addr")
-}
-
-// func StartSniffer(ctx context.Context, ifaceName, ingGwAddr, extClientAddr string, port int) {
-// 	log.Println("Starting Packet Sniffer for iface: ", ifaceName)
-// 	var (
-// 		snapshotLen int32 = 1024
-// 		promiscuous bool  = false
-// 		err         error
-// 		timeout     time.Duration = 1 * time.Microsecond
-// 		handle      *pcap.Handle
-// 	)
-// 	// Open device
-// 	handle, err = pcap.OpenLive(ifaceName, snapshotLen, promiscuous, timeout)
-// 	if err != nil {
-// 		log.Println("failed to start sniffer for iface: ", ifaceName, err)
-// 		return
-// 	}
-// 	// if err := handle.SetBPFFilter(fmt.Sprintf("src %s and port %d", extClientAddr, port)); err != nil {
-// 	// 	log.Println("failed to set bpf filter: ", err)
-// 	// 	return
-// 	// }
-// 	defer handle.Close()
-
-// 	// var tcp layers.TCP
-// 	// var icmp layers.ICMPv4
-// 	// var udp layers.UDP
-// 	// parser := gopacket.NewDecodingLayerParser(layers.LayerTypeIPv4, &udp, &tcp, &icmp)
-
-// 	packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
-// 	for {
-// 		select {
-// 		case <-ctx.Done():
-// 			log.Println("Stopping packet sniffer for iface: ", ifaceName, " port: ", port)
-// 			return
-// 		default:
-// 			packet, err := packetSource.NextPacket()
-// 			if err == nil {
-// 				//processPkt(ifaceName, packet)
-// 				ipLayer := packet.Layer(layers.LayerTypeIPv4)
-// 				if ipLayer != nil {
-// 					fmt.Println("IPv4 layer detected.")
-// 					ip, _ := ipLayer.(*layers.IPv4)
-
-// 					// IP layer variables:
-// 					// Version (Either 4 or 6)
-// 					// IHL (IP Header Length in 32-bit words)
-// 					// TOS, Length, Id, Flags, FragOffset, TTL, Protocol (TCP?),
-// 					// Checksum, SrcIP, DstIP
-// 					fmt.Println("#########################")
-// 					fmt.Printf("From %s to %s\n", ip.SrcIP, ip.DstIP)
-// 					fmt.Println("Protocol: ", ip.Protocol.String())
-// 					if (ip.SrcIP.String() == extClientAddr && ip.DstIP.String() != ingGwAddr) ||
-// 						(ip.DstIP.String() == extClientAddr && ip.SrcIP.String() != ingGwAddr) {
-
-// 						log.Println("-----> Fowarding PKT From: ", ip.SrcIP, " to: ", ip.DstIP)
-// 						c, err := net.Dial("ip", ip.DstIP.String())
-// 						if err == nil {
-// 							c.Write(ip.Payload)
-// 							c.Close()
-// 						} else {
-// 							log.Println("------> Failed to forward packet from sniffer: ", err)
-
-// 						}
-// 					}
-
-// 					fmt.Println("#########################")
-// 				}
-// 			}
-// 		}
-
-// 	}
-// }
-
-// func processPkt(iface string, packet gopacket.Packet) {
-// 	// Let's see if the packet is an ethernet packet
-// 	// ethernetLayer := packet.Layer(layers.LayerTypeEthernet)
-// 	// if ethernetLayer != nil {
-// 	// 	fmt.Println("Ethernet layer detected.")
-// 	// 	ethernetPacket, _ := ethernetLayer.(*layers.Ethernet)
-// 	// 	fmt.Println("Source MAC: ", ethernetPacket.SrcMAC)
-// 	// 	fmt.Println("Destination MAC: ", ethernetPacket.DstMAC)
-// 	// 	// Ethernet type is typically IPv4 but could be ARP or other
-// 	// 	fmt.Println("Ethernet type: ", ethernetPacket.EthernetType)
-// 	// 	fmt.Println()
-// 	// }
-
-// 	// Let's see if the packet is IP (even though the ether type told us)
-// 	ipLayer := packet.Layer(layers.LayerTypeIPv4)
-// 	if ipLayer != nil {
-// 		fmt.Println("IPv4 layer detected.")
-// 		ip, _ := ipLayer.(*layers.IPv4)
-
-// 		// IP layer variables:
-// 		// Version (Either 4 or 6)
-// 		// IHL (IP Header Length in 32-bit words)
-// 		// TOS, Length, Id, Flags, FragOffset, TTL, Protocol (TCP?),
-// 		// Checksum, SrcIP, DstIP
-// 		fmt.Printf("From %s to %s\n", ip.SrcIP, ip.DstIP)
-// 		fmt.Println("Protocol: ", ip.Protocol)
-// 		fmt.Println()
-
-// 	}
-
-// 	// udpLayer := packet.Layer(layers.LayerTypeUDP)
-// 	// if udpLayer != nil {
-// 	// 	udp, _ := udpLayer.(*layers.UDP)
-// 	// 	fmt.Printf("UDP: From port %d to %d\n", udp.SrcPort, udp.DstPort)
-// 	// 	fmt.Println()
-// 	// }
-
-// 	// // Iterate over all layers, printing out each layer type
-// 	// fmt.Println("All packet layers:")
-// 	// for _, layer := range packet.Layers() {
-// 	// 	fmt.Println("- ", layer.LayerType())
-// 	// }
-
-// 	// When iterating through packet.Layers() above,
-// 	// if it lists Payload layer then that is the same as
-// 	// this applicationLayer. applicationLayer contains the payload
-// 	// applicationLayer := packet.ApplicationLayer()
-// 	// if applicationLayer != nil {
-// 	// 	fmt.Println("Application layer/Payload found.")
-// 	// 	fmt.Printf("%s\n", applicationLayer.Payload())
-
-// 	// 	// Search for a string inside the payload
-// 	// 	if strings.Contains(string(applicationLayer.Payload()), "HTTP") {
-// 	// 		fmt.Println("HTTP found!")
-// 	// 	}
-// 	// }
-
-// 	// Check for errors
-// 	if err := packet.ErrorLayer(); err != nil {
-// 		fmt.Println("Error decoding some part of the packet:", err)
-// 	}
-// }

+ 0 - 245
nm-proxy/proxy/proxy_helper.go

@@ -1,245 +0,0 @@
-package proxy
-
-import (
-	"context"
-	"errors"
-	"fmt"
-	"log"
-	"net"
-	"runtime"
-	"strings"
-	"sync"
-	"time"
-
-	"github.com/c-robinson/iplib"
-	"github.com/google/uuid"
-	"github.com/gravitl/netmaker/nm-proxy/common"
-	"github.com/gravitl/netmaker/nm-proxy/metrics"
-	"github.com/gravitl/netmaker/nm-proxy/models"
-	"github.com/gravitl/netmaker/nm-proxy/packet"
-	"github.com/gravitl/netmaker/nm-proxy/server"
-	"github.com/gravitl/netmaker/nm-proxy/stun"
-	"github.com/gravitl/netmaker/nm-proxy/wg"
-)
-
-func NewProxy(config models.ProxyConfig) *Proxy {
-	p := &Proxy{Config: config}
-	p.Ctx, p.Cancel = context.WithCancel(context.Background())
-	return p
-}
-
-func (p *Proxy) proxyToRemote(wg *sync.WaitGroup) {
-	ticker := time.NewTicker(time.Minute)
-	defer ticker.Stop()
-	buf := make([]byte, 65000)
-	defer wg.Done()
-	for {
-		select {
-		case <-p.Ctx.Done():
-			return
-		default:
-
-			n, err := p.LocalConn.Read(buf)
-			if err != nil {
-				log.Println("ERRR READ: ", err)
-				continue
-			}
-
-			// if _, found := common.GetPeer(p.Config.RemoteKey); !found {
-			// 	log.Printf("Peer: %s not found in config\n", p.Config.RemoteKey)
-			// 	p.Close()
-			// 	return
-			// }
-			go func(n int, peerKey string) {
-				metrics.MetricsMapLock.Lock()
-				metric := metrics.MetricsMap[peerKey]
-				metric.TrafficSent += float64(n) / (1 << 20)
-				metrics.MetricsMap[peerKey] = metric
-				metrics.MetricsMapLock.Unlock()
-			}(n, p.Config.RemoteKey.String())
-
-			//var srcPeerKeyHash, dstPeerKeyHash string
-			if !p.Config.IsExtClient {
-				buf, n, _, _ = packet.ProcessPacketBeforeSending(buf, n, p.Config.WgInterface.Device.PublicKey.String(), p.Config.RemoteKey.String())
-				if err != nil {
-					log.Println("failed to process pkt before sending: ", err)
-				}
-			}
-
-			// log.Printf("PROXING TO REMOTE!!!---> %s >>>>> %s >>>>> %s [[ SrcPeerHash: %s, DstPeerHash: %s ]]\n",
-			// 	p.LocalConn.LocalAddr(), server.NmProxyServer.Server.LocalAddr().String(), p.RemoteConn.String(), srcPeerKeyHash, dstPeerKeyHash)
-
-			_, err = server.NmProxyServer.Server.WriteToUDP(buf[:n], p.RemoteConn)
-			if err != nil {
-				log.Println("Failed to send to remote: ", err)
-			}
-
-		}
-	}
-
-}
-
-func (p *Proxy) Reset() {
-	p.Close()
-	if err := p.pullLatestConfig(); err != nil {
-		log.Println("couldn't perform reset: ", err)
-		return
-	}
-	p.Start()
-
-}
-
-func (p *Proxy) pullLatestConfig() error {
-	peer, found := common.GetPeer(p.Config.RemoteKey)
-	if found {
-		p.Config.PeerEndpoint.Port = peer.Config.PeerEndpoint.Port
-	} else {
-		return errors.New("peer not found")
-	}
-	return nil
-
-}
-
-func (p *Proxy) startMetricsThread(wg *sync.WaitGroup, rTicker *time.Ticker) {
-	ticker := time.NewTicker(time.Minute)
-	defer ticker.Stop()
-	defer wg.Done()
-	for {
-		select {
-		case <-p.Ctx.Done():
-			return
-		case <-ticker.C:
-			metrics.MetricsMapLock.Lock()
-			metric := metrics.MetricsMap[p.Config.RemoteKey.String()]
-			if metric.ConnectionStatus {
-				rTicker.Reset(*p.Config.PersistentKeepalive)
-			}
-			metric.ConnectionStatus = false
-			metrics.MetricsMap[p.Config.RemoteKey.String()] = metric
-			metrics.MetricsMapLock.Unlock()
-			pkt, err := packet.CreateMetricPacket(uuid.New().ID(), p.Config.LocalKey, p.Config.RemoteKey)
-			if err == nil {
-				log.Printf("-----------> ##### $$$$$ SENDING METRIC PACKET TO: %s\n", p.RemoteConn.String())
-				_, err = server.NmProxyServer.Server.WriteToUDP(pkt, p.RemoteConn)
-				if err != nil {
-					log.Println("Failed to send to metric pkt: ", err)
-				}
-
-			}
-		}
-	}
-}
-
-func (p *Proxy) peerUpdates(wg *sync.WaitGroup, ticker *time.Ticker) {
-	defer wg.Done()
-	for {
-		select {
-		case <-p.Ctx.Done():
-			return
-		case <-ticker.C:
-			// send listen port packet
-			m := &packet.ProxyUpdateMessage{
-				Type:       packet.MessageProxyType,
-				Action:     packet.UpdateListenPort,
-				Sender:     p.Config.LocalKey,
-				Reciever:   p.Config.RemoteKey,
-				ListenPort: uint32(stun.Host.PrivPort),
-			}
-			pkt, err := packet.CreateProxyUpdatePacket(m)
-			if err == nil {
-				log.Printf("-----------> ##### $$$$$ SENDING Proxy Update PACKET TO: %s\n", p.RemoteConn.String())
-				_, err = server.NmProxyServer.Server.WriteToUDP(pkt, p.RemoteConn)
-				if err != nil {
-					log.Println("Failed to send to metric pkt: ", err)
-				}
-
-			}
-		}
-	}
-}
-
-// ProxyPeer proxies everything from Wireguard to the RemoteKey peer and vice-versa
-func (p *Proxy) ProxyPeer() {
-	ticker := time.NewTicker(*p.Config.PersistentKeepalive)
-	defer ticker.Stop()
-	wg := &sync.WaitGroup{}
-	wg.Add(1)
-	go p.proxyToRemote(wg)
-	// if common.BehindNAT {
-	wg.Add(1)
-	go p.startMetricsThread(wg, ticker)
-	wg.Add(1)
-	go p.peerUpdates(wg, ticker)
-	// }
-	wg.Wait()
-
-}
-func test(n int, buffer []byte) {
-	data := buffer[:n]
-	srcKeyHash := data[n-32 : n-16]
-	dstKeyHash := data[n-16:]
-	log.Printf("--------> TEST PACKET [ SRCKEYHASH: %x ], [ DSTKEYHASH: %x ] \n", srcKeyHash, dstKeyHash)
-}
-
-func (p *Proxy) updateEndpoint() error {
-	udpAddr, err := net.ResolveUDPAddr("udp", p.LocalConn.LocalAddr().String())
-	if err != nil {
-		return err
-	}
-	// add local proxy connection as a Wireguard peer
-	log.Printf("---> ####### Updating Peer:  %+v\n", p.Config.PeerConf)
-	err = p.Config.WgInterface.UpdatePeer(p.Config.RemoteKey.String(), p.Config.PeerConf.AllowedIPs, wg.DefaultWgKeepAlive,
-		udpAddr, p.Config.PeerConf.PresharedKey)
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-func GetFreeIp(cidrAddr string, dstPort int) (string, error) {
-	//ensure AddressRange is valid
-	if dstPort == 0 {
-		return "", errors.New("dst port should be set")
-	}
-	if _, _, err := net.ParseCIDR(cidrAddr); err != nil {
-		log.Println("UniqueAddress encountered  an error")
-		return "", err
-	}
-	net4 := iplib.Net4FromStr(cidrAddr)
-	newAddrs := net4.FirstAddress()
-	for {
-		if runtime.GOOS == "darwin" {
-			_, err := common.RunCmd(fmt.Sprintf("ifconfig lo0 alias %s 255.255.255.255", newAddrs.String()), true)
-			if err != nil {
-				log.Println("Failed to add alias: ", err)
-			}
-		}
-
-		conn, err := net.DialUDP("udp", &net.UDPAddr{
-			IP:   net.ParseIP(newAddrs.String()),
-			Port: models.NmProxyPort,
-		}, &net.UDPAddr{
-			IP:   net.ParseIP("127.0.0.1"),
-			Port: dstPort,
-		})
-		if err != nil {
-			log.Println("----> GetFreeIP ERR: ", err)
-			if strings.Contains(err.Error(), "can't assign requested address") ||
-				strings.Contains(err.Error(), "address already in use") || strings.Contains(err.Error(), "cannot assign requested address") {
-				var nErr error
-				newAddrs, nErr = net4.NextIP(newAddrs)
-				if nErr != nil {
-					return "", nErr
-				}
-			} else {
-				return "", err
-			}
-		}
-		if err == nil {
-			conn.Close()
-			return newAddrs.String(), nil
-		}
-
-	}
-}

+ 0 - 285
nm-proxy/server/server.go

@@ -1,285 +0,0 @@
-package server
-
-import (
-	"context"
-	"encoding/binary"
-	"fmt"
-	"log"
-	"net"
-	"time"
-
-	"github.com/gravitl/netmaker/nm-proxy/common"
-	"github.com/gravitl/netmaker/nm-proxy/metrics"
-	"github.com/gravitl/netmaker/nm-proxy/models"
-	"github.com/gravitl/netmaker/nm-proxy/packet"
-)
-
-var (
-	NmProxyServer = &ProxyServer{}
-)
-
-const (
-	defaultBodySize = 10000
-	defaultPort     = models.NmProxyPort
-)
-
-type Config struct {
-	Port     int
-	BodySize int
-	IsRelay  bool
-	Addr     net.Addr
-}
-
-type ProxyServer struct {
-	Config Config
-	Server *net.UDPConn
-}
-
-func (p *ProxyServer) Close() {
-	log.Println("--------->### Shutting down Proxy.....")
-	// clean up proxy connections
-	for _, peerI := range common.WgIfaceMap.PeerMap {
-		peerI.Mutex.Lock()
-		peerI.StopConn()
-		peerI.Mutex.Unlock()
-	}
-	// close server connection
-	NmProxyServer.Server.Close()
-}
-
-// Proxy.Listen - begins listening for packets
-func (p *ProxyServer) Listen(ctx context.Context) {
-
-	// Buffer with indicated body size
-	buffer := make([]byte, 65036)
-	for {
-
-		select {
-		case <-ctx.Done():
-			p.Close()
-			return
-		default:
-			// Read Packet
-
-			n, source, err := p.Server.ReadFromUDP(buffer)
-			if err != nil || source == nil { // in future log errors?
-				log.Println("RECV ERROR: ", err)
-				continue
-			}
-			//go func(buffer []byte, source *net.UDPAddr, n int) {
-			proxyTransportMsg := true
-			var srcPeerKeyHash, dstPeerKeyHash string
-			n, srcPeerKeyHash, dstPeerKeyHash, err = packet.ExtractInfo(buffer, n)
-			if err != nil {
-				log.Println("proxy transport message not found: ", err)
-				proxyTransportMsg = false
-			}
-			if proxyTransportMsg {
-				p.proxyIncomingPacket(buffer[:], source, n, srcPeerKeyHash, dstPeerKeyHash)
-				continue
-			} else {
-				// unknown peer to proxy -> check if extclient and handle it
-				if handleExtClients(buffer[:], n, source) {
-					continue
-				}
-
-			}
-			handleMsgs(buffer, n, source)
-
-		}
-	}
-}
-
-func handleMsgs(buffer []byte, n int, source *net.UDPAddr) {
-
-	msgType := binary.LittleEndian.Uint32(buffer[:4])
-	switch packet.MessageType(msgType) {
-	case packet.MessageMetricsType:
-		metricMsg, err := packet.ConsumeMetricPacket(buffer[:n])
-		// calc latency
-		if err == nil {
-			log.Printf("------->$$$$$ Recieved Metric Pkt: %+v, FROM:%s\n", metricMsg, source.String())
-			if metricMsg.Sender == common.WgIfaceMap.Iface.PublicKey {
-				latency := time.Now().UnixMilli() - metricMsg.TimeStamp
-				metrics.MetricsMapLock.Lock()
-				metric := metrics.MetricsMap[metricMsg.Reciever.String()]
-				metric.LastRecordedLatency = uint64(latency)
-				metric.ConnectionStatus = true
-				metric.TrafficRecieved += float64(n) / (1 << 20)
-				metrics.MetricsMap[metricMsg.Reciever.String()] = metric
-				metrics.MetricsMapLock.Unlock()
-			} else if metricMsg.Reciever == common.WgIfaceMap.Iface.PublicKey {
-				// proxy it back to the sender
-				log.Println("------------> $$$ SENDING back the metric pkt to the source: ", source.String())
-				_, err = NmProxyServer.Server.WriteToUDP(buffer[:n], source)
-				if err != nil {
-					log.Println("Failed to send metric packet to remote: ", err)
-				}
-				metrics.MetricsMapLock.Lock()
-				metric := metrics.MetricsMap[metricMsg.Sender.String()]
-				metric.ConnectionStatus = true
-				metric.TrafficRecieved += float64(n) / (1 << 20)
-				metrics.MetricsMap[metricMsg.Sender.String()] = metric
-				metrics.MetricsMapLock.Unlock()
-			}
-		}
-	case packet.MessageProxyUpdateType:
-		msg, err := packet.ConsumeProxyUpdateMsg(buffer[:n])
-		if err == nil {
-			switch msg.Action {
-			case packet.UpdateListenPort:
-				if peer, ok := common.WgIfaceMap.PeerMap[msg.Sender.String()]; ok {
-					peer.Mutex.Lock()
-					if peer.Config.PeerEndpoint.Port != int(msg.ListenPort) {
-						// update peer conn
-						peer.Config.PeerEndpoint.Port = int(msg.ListenPort)
-						common.WgIfaceMap.PeerMap[msg.Sender.String()] = peer
-						log.Println("--------> Resetting Proxy Conn For Peer ", msg.Sender.String())
-						peer.Mutex.Unlock()
-						peer.ResetConn()
-						return
-					}
-					peer.Mutex.Unlock()
-
-				}
-			}
-		}
-	// consume handshake message for ext clients
-	case packet.MessageInitiationType:
-
-		err := packet.ConsumeHandshakeInitiationMsg(false, buffer[:n], source,
-			packet.NoisePublicKey(common.WgIfaceMap.Iface.PublicKey), packet.NoisePrivateKey(common.WgIfaceMap.Iface.PrivateKey))
-		if err != nil {
-			log.Println("---------> @@@ failed to decode HS: ", err)
-		}
-	}
-}
-
-func handleExtClients(buffer []byte, n int, source *net.UDPAddr) bool {
-	isExtClient := false
-	if peerInfo, ok := common.ExtSourceIpMap[source.String()]; ok {
-		if peerI, ok := common.WgIfaceMap.PeerMap[peerInfo.PeerKey]; ok {
-			peerI.Mutex.RLock()
-			peerI.Config.RecieverChan <- buffer[:n]
-			metrics.MetricsMapLock.Lock()
-			metric := metrics.MetricsMap[peerInfo.PeerKey]
-			metric.TrafficRecieved += float64(n) / (1 << 20)
-			metric.ConnectionStatus = true
-			metrics.MetricsMap[peerInfo.PeerKey] = metric
-			metrics.MetricsMapLock.Unlock()
-			peerI.Mutex.RUnlock()
-			isExtClient = true
-		}
-
-	}
-	return isExtClient
-}
-
-func (p *ProxyServer) proxyIncomingPacket(buffer []byte, source *net.UDPAddr, n int, srcPeerKeyHash, dstPeerKeyHash string) {
-	var err error
-	//log.Printf("--------> RECV PKT , [SRCKEYHASH: %s], SourceIP: [%s] \n", srcPeerKeyHash, source.IP.String())
-
-	if common.WgIfaceMap.IfaceKeyHash != dstPeerKeyHash && common.IsRelay {
-
-		log.Println("----------> Relaying######")
-		// check for routing map and forward to right proxy
-		if remoteMap, ok := common.RelayPeerMap[srcPeerKeyHash]; ok {
-			if conf, ok := remoteMap[dstPeerKeyHash]; ok {
-				log.Printf("--------> Relaying PKT [ SourceIP: %s:%d ], [ SourceKeyHash: %s ], [ DstIP: %s:%d ], [ DstHashKey: %s ] \n",
-					source.IP.String(), source.Port, srcPeerKeyHash, conf.Endpoint.String(), conf.Endpoint.Port, dstPeerKeyHash)
-				_, err = p.Server.WriteToUDP(buffer[:n+packet.MessageProxySize], conf.Endpoint)
-				if err != nil {
-					log.Println("Failed to send to remote: ", err)
-				}
-				return
-			}
-		} else {
-			if remoteMap, ok := common.RelayPeerMap[dstPeerKeyHash]; ok {
-				if conf, ok := remoteMap[dstPeerKeyHash]; ok {
-					log.Printf("--------> Relaying BACK TO RELAYED NODE PKT [ SourceIP: %s ], [ SourceKeyHash: %s ], [ DstIP: %s ], [ DstHashKey: %s ] \n",
-						source.String(), srcPeerKeyHash, conf.Endpoint.String(), dstPeerKeyHash)
-					_, err = p.Server.WriteToUDP(buffer[:n+packet.MessageProxySize], conf.Endpoint)
-					if err != nil {
-						log.Println("Failed to send to remote: ", err)
-					}
-					return
-				}
-			}
-
-		}
-	}
-
-	if peerInfo, ok := common.PeerKeyHashMap[srcPeerKeyHash]; ok {
-
-		log.Printf("PROXING TO LOCAL!!!---> %s <<<< %s <<<<<<<< %s   [[ RECV PKT [SRCKEYHASH: %s], [DSTKEYHASH: %s], SourceIP: [%s] ]]\n",
-			peerInfo.LocalConn.RemoteAddr(), peerInfo.LocalConn.LocalAddr(),
-			fmt.Sprintf("%s:%d", source.IP.String(), source.Port), srcPeerKeyHash, dstPeerKeyHash, source.IP.String())
-		_, err = peerInfo.LocalConn.Write(buffer[:n])
-		if err != nil {
-			log.Println("Failed to proxy to Wg local interface: ", err)
-			//continue
-		}
-
-		go func(n int, peerKey string) {
-			metrics.MetricsMapLock.Lock()
-			metric := metrics.MetricsMap[peerKey]
-			metric.TrafficRecieved += float64(n) / (1 << 20)
-			metric.ConnectionStatus = true
-			metrics.MetricsMap[peerKey] = metric
-			metrics.MetricsMapLock.Unlock()
-		}(n, peerInfo.PeerKey)
-		return
-
-	}
-
-}
-
-// Create - creats a proxy listener
-// port - port for proxy to listen on localhost
-// bodySize - default 10000, leave 0 to use default
-// addr - the address for proxy to listen on
-// forwards - indicate address to forward to, {"<address:port>",...} format
-func (p *ProxyServer) CreateProxyServer(port, bodySize int, addr string) (err error) {
-	if p == nil {
-		p = &ProxyServer{}
-	}
-	p.Config.Port = port
-	p.Config.BodySize = bodySize
-	p.setDefaults()
-	p.Server, err = net.ListenUDP("udp", &net.UDPAddr{
-		Port: p.Config.Port,
-		IP:   net.ParseIP(addr),
-	})
-	return
-}
-
-func (p *ProxyServer) KeepAlive(ip string, port int) {
-	for {
-		_, _ = p.Server.WriteToUDP([]byte("hello-proxy"), &net.UDPAddr{
-			IP:   net.ParseIP(ip),
-			Port: port,
-		})
-		//log.Println("Sending MSg: ", ip, port, err)
-		time.Sleep(time.Second * 5)
-	}
-}
-
-// Proxy.setDefaults - sets all defaults of proxy listener
-func (p *ProxyServer) setDefaults() {
-	p.setDefaultBodySize()
-	p.setDefaultPort()
-}
-
-// Proxy.setDefaultPort - sets default port of Proxy listener if 0
-func (p *ProxyServer) setDefaultPort() {
-	if p.Config.Port == 0 {
-		p.Config.Port = defaultPort
-	}
-}
-
-// Proxy.setDefaultBodySize - sets default body size of Proxy listener if 0
-func (p *ProxyServer) setDefaultBodySize() {
-	if p.Config.BodySize == 0 {
-		p.Config.BodySize = defaultBodySize
-	}
-}

+ 0 - 69
nm-proxy/stun/stun.go

@@ -1,69 +0,0 @@
-package stun
-
-import (
-	"fmt"
-	"log"
-	"net"
-	"strconv"
-	"strings"
-
-	"github.com/gravitl/netmaker/nm-proxy/models"
-	"gortc.io/stun"
-)
-
-type HostInfo struct {
-	PublicIp net.IP
-	PrivIp   net.IP
-	PubPort  int
-	PrivPort int
-}
-
-var Host HostInfo
-
-func GetHostInfo(stunHostAddr string) (info HostInfo) {
-
-	s, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:3478", stunHostAddr))
-	if err != nil {
-		log.Println("Resolve: ", err)
-		return
-	}
-	l := &net.UDPAddr{
-		IP:   net.ParseIP(""),
-		Port: models.NmProxyPort,
-	}
-	conn, err := net.DialUDP("udp", l, s)
-	if err != nil {
-		log.Println(err)
-		return
-	}
-	defer conn.Close()
-	c, err := stun.NewClient(conn)
-	if err != nil {
-		log.Println(err)
-		return
-	}
-	defer c.Close()
-	re := strings.Split(conn.LocalAddr().String(), ":")
-	info.PrivIp = net.ParseIP(re[0])
-	info.PrivPort, _ = strconv.Atoi(re[1])
-	// Building binding request with random transaction id.
-	message := stun.MustBuild(stun.TransactionID, stun.BindingRequest)
-	// Sending request to STUN server, waiting for response message.
-	if err := c.Do(message, func(res stun.Event) {
-		if res.Error != nil {
-			log.Println("stun error: ", res.Error)
-			return
-		}
-		// Decoding XOR-MAPPED-ADDRESS attribute from message.
-		var xorAddr stun.XORMappedAddress
-		if err := xorAddr.GetFrom(res.Message); err != nil {
-			log.Println("stun error: ", res.Error)
-			return
-		}
-		info.PublicIp = xorAddr.IP
-		info.PubPort = xorAddr.Port
-	}); err != nil {
-		log.Println("stun error: ", err)
-	}
-	return
-}

+ 0 - 321
nm-proxy/wg/wg.go

@@ -1,321 +0,0 @@
-package wg
-
-import (
-	"errors"
-	"fmt"
-	"log"
-	"net"
-	"os"
-	"os/exec"
-	"strings"
-	"sync"
-	"time"
-
-	"golang.zx2c4.com/wireguard/wgctrl"
-	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
-)
-
-const (
-	DefaultMTU         = 1280
-	DefaultWgPort      = 51820
-	DefaultWgKeepAlive = 20 * time.Second
-)
-
-// WGIface represents a interface instance
-type WGIface struct {
-	Name      string
-	Port      int
-	MTU       int
-	Device    *wgtypes.Device
-	Address   WGAddress
-	Interface NetInterface
-	mu        sync.Mutex
-}
-
-// NetInterface represents a generic network tunnel interface
-type NetInterface interface {
-	Close() error
-}
-
-// WGAddress Wireguard parsed address
-type WGAddress struct {
-	IP      net.IP
-	Network *net.IPNet
-}
-
-// NewWGIFace Creates a new Wireguard interface instance
-func NewWGIFace(iface string, address string, mtu int) (*WGIface, error) {
-	wgIface := &WGIface{
-		Name: iface,
-		MTU:  mtu,
-		mu:   sync.Mutex{},
-	}
-
-	wgAddress, err := parseAddress(address)
-	if err != nil {
-		return wgIface, err
-	}
-
-	wgIface.Address = wgAddress
-	err = wgIface.GetWgIface(iface)
-	if err != nil {
-		return nil, err
-	}
-	return wgIface, nil
-}
-
-func (w *WGIface) GetWgIface(iface string) error {
-	wgClient, err := wgctrl.New()
-	if err != nil {
-		return err
-	}
-	dev, err := wgClient.Device(iface)
-	if err != nil {
-		return err
-	}
-
-	//log.Printf("----> DEVICE: %+v\n", dev)
-	w.Device = dev
-	w.Port = dev.ListenPort
-	return nil
-}
-
-func GetWgIfacePubKey(iface string) [32]byte {
-	wgClient, err := wgctrl.New()
-	if err != nil {
-		log.Println("Error fetching pub key: ", iface, err)
-		return [32]byte{}
-	}
-	dev, err := wgClient.Device(iface)
-	if err != nil {
-		log.Println("Error fetching pub key: ", iface, err)
-		return [32]byte{}
-	}
-
-	return dev.PublicKey
-}
-
-func GetWgIfacePrivKey(iface string) [32]byte {
-	wgClient, err := wgctrl.New()
-	if err != nil {
-		log.Println("Error fetching pub key: ", iface, err)
-		return [32]byte{}
-	}
-	dev, err := wgClient.Device(iface)
-	if err != nil {
-		log.Println("Error fetching pub key: ", iface, err)
-		return [32]byte{}
-	}
-	return dev.PrivateKey
-}
-
-// parseAddress parse a string ("1.2.3.4/24") address to WG Address
-func parseAddress(address string) (WGAddress, error) {
-	ip, network, err := net.ParseCIDR(address)
-	if err != nil {
-		return WGAddress{}, err
-	}
-	return WGAddress{
-		IP:      ip,
-		Network: network,
-	}, nil
-}
-
-// UpdatePeer updates existing Wireguard Peer or creates a new one if doesn't exist
-func (w *WGIface) UpdatePeer(peerKey string, allowedIps []net.IPNet, keepAlive time.Duration, endpoint *net.UDPAddr, preSharedKey *wgtypes.Key) error {
-	w.mu.Lock()
-	defer w.mu.Unlock()
-
-	log.Printf("updating interface %s peer %s: endpoint %s ", w.Name, peerKey, endpoint)
-
-	// //parse allowed ips
-	// _, ipNet, err := net.ParseCIDR(allowedIps)
-	// if err != nil {
-	// 	return err
-	// }
-
-	peerKeyParsed, err := wgtypes.ParseKey(peerKey)
-	if err != nil {
-		return err
-	}
-	peer := wgtypes.PeerConfig{
-		PublicKey:                   peerKeyParsed,
-		ReplaceAllowedIPs:           true,
-		AllowedIPs:                  allowedIps,
-		PersistentKeepaliveInterval: &keepAlive,
-		PresharedKey:                preSharedKey,
-		Endpoint:                    endpoint,
-	}
-
-	config := wgtypes.Config{
-		Peers: []wgtypes.PeerConfig{peer},
-	}
-	err = w.configureDevice(config)
-	if err != nil {
-		return fmt.Errorf("received error \"%v\" while updating peer on interface %s with settings: allowed ips %s, endpoint %s", err, w.Name, allowedIps, endpoint.String())
-	}
-	return nil
-}
-
-// configureDevice configures the wireguard device
-func (w *WGIface) configureDevice(config wgtypes.Config) error {
-	wg, err := wgctrl.New()
-	if err != nil {
-		return err
-	}
-	defer wg.Close()
-
-	// validate if device with name exists
-	_, err = wg.Device(w.Name)
-	if err != nil {
-		return err
-	}
-	log.Printf("got Wireguard device %s\n", w.Name)
-
-	return wg.ConfigureDevice(w.Name, config)
-}
-
-// GetListenPort returns the listening port of the Wireguard endpoint
-func (w *WGIface) GetListenPort() (*int, error) {
-	log.Printf("getting Wireguard listen port of interface %s", w.Name)
-
-	//discover Wireguard current configuration
-	wg, err := wgctrl.New()
-	if err != nil {
-		return nil, err
-	}
-	defer wg.Close()
-
-	d, err := wg.Device(w.Name)
-	if err != nil {
-		return nil, err
-	}
-	log.Printf("got Wireguard device listen port %s, %d", w.Name, d.ListenPort)
-
-	return &d.ListenPort, nil
-}
-
-// GetRealIface - retrieves tun iface based on reference iface name from config file
-func GetRealIface(iface string) (string, error) {
-	RunCmd("wg show interfaces", false)
-	ifacePath := "/var/run/wireguard/" + iface + ".name"
-	if !(FileExists(ifacePath)) {
-		return "", errors.New(ifacePath + " does not exist")
-	}
-	realIfaceName, err := GetFileAsString(ifacePath)
-	if err != nil {
-		return "", err
-	}
-	realIfaceName = strings.TrimSpace(realIfaceName)
-	if !(FileExists(fmt.Sprintf("/var/run/wireguard/%s.sock", realIfaceName))) {
-		return "", errors.New("interface file does not exist")
-	}
-	return realIfaceName, nil
-}
-
-// FileExists - checks if file exists locally
-func FileExists(f string) bool {
-	info, err := os.Stat(f)
-	if os.IsNotExist(err) {
-		return false
-	}
-	if err != nil && strings.Contains(err.Error(), "not a directory") {
-		return false
-	}
-	if err != nil {
-		log.Println(0, "error reading file: "+f+", "+err.Error())
-	}
-	return !info.IsDir()
-}
-
-// GetFileAsString - returns the string contents of a given file
-func GetFileAsString(path string) (string, error) {
-	content, err := os.ReadFile(path)
-	if err != nil {
-		return "", err
-	}
-	return string(content), err
-}
-
-// RunCmd - runs a local command
-func RunCmd(command string, printerr bool) (string, error) {
-	args := strings.Fields(command)
-	cmd := exec.Command(args[0], args[1:]...)
-	cmd.Wait()
-	out, err := cmd.CombinedOutput()
-	if err != nil && printerr {
-		log.Println("error running command: ", command)
-		log.Println(strings.TrimSuffix(string(out), "\n"))
-	}
-	return string(out), err
-}
-
-// RemovePeer removes a Wireguard Peer from the interface iface
-func (w *WGIface) RemovePeer(peerKey string) error {
-	w.mu.Lock()
-	defer w.mu.Unlock()
-
-	log.Printf("Removing peer %s from interface %s ", peerKey, w.Name)
-
-	peerKeyParsed, err := wgtypes.ParseKey(peerKey)
-	if err != nil {
-		return err
-	}
-
-	peer := wgtypes.PeerConfig{
-		PublicKey: peerKeyParsed,
-		Remove:    true,
-	}
-
-	config := wgtypes.Config{
-		Peers: []wgtypes.PeerConfig{peer},
-	}
-	err = w.configureDevice(config)
-	if err != nil {
-		return fmt.Errorf("received error \"%v\" while removing peer %s from interface %s", err, peerKey, w.Name)
-	}
-	return nil
-}
-
-// UpdatePeer
-func (w *WGIface) Update(peerConf wgtypes.PeerConfig, updateOnly bool) error {
-	w.mu.Lock()
-	defer w.mu.Unlock()
-	var err error
-	log.Printf("---------> NEWWWWWW Updating peer %+v from interface %s ", peerConf, w.Name)
-
-	peerConf.UpdateOnly = updateOnly
-	peerConf.ReplaceAllowedIPs = true
-	config := wgtypes.Config{
-		Peers: []wgtypes.PeerConfig{peerConf},
-	}
-	err = w.configureDevice(config)
-	if err != nil {
-		return fmt.Errorf("received error \"%v\" while Updating peer %s from interface %s", err, peerConf.PublicKey.String(), w.Name)
-	}
-	return nil
-}
-
-func GetPeer(ifaceName, peerPubKey string) (wgtypes.Peer, error) {
-	wg, err := wgctrl.New()
-	if err != nil {
-		return wgtypes.Peer{}, err
-	}
-	defer func() {
-		err = wg.Close()
-		if err != nil {
-			log.Printf("got error while closing wgctl: %v", err)
-		}
-	}()
-
-	wgDevice, err := wg.Device(ifaceName)
-	if err != nil {
-		return wgtypes.Peer{}, err
-	}
-	for _, peer := range wgDevice.Peers {
-		if peer.PublicKey.String() == peerPubKey {
-			return peer, nil
-		}
-	}
-	return wgtypes.Peer{}, fmt.Errorf("peer not found")
-}

+ 509 - 0
scripts/nm-upgrade.sh

@@ -0,0 +1,509 @@
+#!/bin/bash
+
+# check_version - make sure current version is 0.17.1 before continuing
+check_version() {
+  IMG_TAG=$(yq -r '.services.netmaker.image' docker-compose.yml)
+
+  if [[ "$IMG_TAG" == *"v0.17.1"* ]]; then
+      echo "version is $IMG_TAG"
+  else
+      echo "error, current version is $IMG_TAG"
+      echo "please upgrade to v0.17.1 in order to use the upgrade script"
+      exit 1
+  fi
+}
+
+# wait_seconds - wait a number of seconds, print a log
+wait_seconds() {
+  for ((a=1; a <= $1; a++))
+  do
+    echo ". . ."
+    sleep 1
+  done
+}
+
+# confirm - confirm a choice, or exit script
+confirm() {
+  while true; do
+      read -p 'Does everything look right? [y/n]: ' yn
+      case $yn in
+          [Yy]* ) override="true"; break;;
+          [Nn]* ) echo "exiting..."; exit 1;;
+          * ) echo "Please answer yes or no.";;
+      esac
+  done
+}
+
+# install_dependencies - install system dependencies necessary for script to run
+install_dependencies() {
+  OS=$(uname)
+  is_ubuntu=$(sudo cat /etc/lsb-release | grep "Ubuntu")
+  if [ "${is_ubuntu}" != "" ]; then
+    dependencies="yq jq wireguard jq docker.io docker-compose"
+    update_cmd='apt update'
+    install_cmd='snap install'
+  elif [ -f /etc/debian_version ]; then
+    dependencies="yq jq wireguard jq docker.io docker-compose"
+    update_cmd='apt update'
+    install_cmd='apt install -y'
+  elif [ -f /etc/centos-release ]; then
+    dependencies="wireguard jq docker.io docker-compose"
+    update_cmd='yum update'
+    install_cmd='yum install -y'
+  elif [ -f /etc/fedora-release ]; then
+    dependencies="wireguard jq docker.io docker-compose"
+    update_cmd='dnf update'
+    install_cmd='dnf install -y'
+  elif [ -f /etc/redhat-release ]; then
+    dependencies="wireguard jq docker.io docker-compose"
+    update_cmd='yum update'
+    install_cmd='yum install -y'
+  elif [ -f /etc/arch-release ]; then
+        dependecies="wireguard-tools jq docker.io docker-compose netclient"
+    update_cmd='pacman -Sy'
+    install_cmd='pacman -S --noconfirm'
+  else
+    echo "OS not supported for automatic install"
+      exit 1
+  fi
+
+  set -- $dependencies
+
+  ${update_cmd}
+
+  set +e
+  while [ -n "$1" ]; do
+      is_installed=$(dpkg-query -W --showformat='${Status}\n' $1 | grep "install ok installed")
+      if [ "${is_installed}" != "" ]; then
+          echo "    " $1 is installed
+      else
+          echo "    " $1 is not installed. Attempting install.
+          ${install_cmd} $1
+          sleep 5
+          if [ "${OS}" = "OpenWRT" ] || [ "${OS}" = "TurrisOS" ]; then
+              is_installed=$(opkg list-installed $1 | grep $1)
+          else
+              is_installed=$(dpkg-query -W --showformat='${Status}\n' $1 | grep "install ok installed")
+          fi
+          if [ "${is_installed}" != "" ]; then
+              echo "    " $1 is installed
+          elif [ -x "$(command -v $1)" ]; then
+              echo "  " $1 is installed
+          else
+              echo "  " FAILED TO INSTALL $1
+              echo "  " This may break functionality.
+          fi
+      fi
+    shift
+  done
+  set -e
+  
+  echo "-----------------------------------------------------"
+  echo "dependency install complete"
+  echo "-----------------------------------------------------"
+}
+
+# collect_server_settings - retrieve server settings from existing compose file
+collect_server_settings() {
+  MASTER_KEY=$(yq -r .services.netmaker.environment.MASTER_KEY docker-compose.yml)
+  echo "-----------------------------------------------------"
+  echo "Is $MASTER_KEY the correct master key for your Netmaker installation?"
+  echo "-----------------------------------------------------"
+  select mkey_option in "yes" "no (enter manually)"; do
+    case $REPLY in
+      1)
+        echo "using $MASTER_KEY for master key"
+      break
+        ;;      
+      2)
+        read -p "Enter Master Key: " mkey
+        MASTER_KEY=$mkey
+        echo "using $MASTER_KEY"
+        break
+        ;;
+      *) echo "invalid option $REPLY, choose 1 or 2";;
+    esac
+  done
+
+  SERVER_HTTP_HOST=$(yq -r .services.netmaker.environment.SERVER_HTTP_HOST docker-compose.yml)
+  echo "-----------------------------------------------------"
+  echo "Is $SERVER_HTTP_HOST the correct api endpoint for your Netmaker installation?"
+  echo "-----------------------------------------------------"
+  select endpoint_option in "yes" "no (enter manually)"; do
+    case $REPLY in
+      1)
+        echo "using $SERVER_HTTP_HOST for api endpoint"
+      break
+        ;;      
+      2)
+        read -p "Enter API Endpoint: " endpoint
+        SERVER_HTTP_HOST=$endpoint
+        echo "using $SERVER_HTTP_HOST"
+        break
+        ;;
+      *) echo "invalid option $REPLY";;
+    esac
+  done
+
+  BROKER_NAME=$(yq -r .services.netmaker.environment.SERVER_NAME docker-compose.yml)
+  echo "-----------------------------------------------------"
+  echo "Is $BROKER_NAME the correct domain for your MQ broker?"
+  echo "-----------------------------------------------------"
+  select broker_option in "yes" "no (enter manually)"; do
+    case $REPLY in
+      1)
+        echo "using $BROKER_NAME for endpoint"
+      break
+        ;;      
+      2)
+        read -p "Enter Broker Domain: " broker
+        BROKER_NAME=$broker
+        echo "using $BROKER_NAME"
+        break
+        ;;
+      *) echo "invalid option $REPLY";;
+    esac
+  done
+
+  SERVER_NAME=${BROKER_NAME#"broker."}
+  echo "-----------------------------------------------------"
+  echo "Is $SERVER_NAME the correct base domain for your installation?"
+  echo "-----------------------------------------------------"
+  select domain_option in "yes" "no (enter manually)"; do
+    case $REPLY in
+      1)
+        echo "using $SERVER_NAME for domain"
+      break
+        ;;      
+      2)
+        read -p "Enter Server Domain: " broker
+        SERVER_NAME=$server
+        echo "using $SERVER_NAME"
+        break
+        ;;
+      *) echo "invalid option $REPLY";;
+    esac
+  done
+
+  STUN_NAME="stun.$SERVER_NAME"
+  echo "-----------------------------------------------------"
+  echo "Netmaker v0.18.0 requires a new DNS entry for $STUN_NAME."
+  echo "Please confirm this is added to your DNS provider before continuing"
+  echo "(note: this is not required if using an nip.io address)"
+  echo "-----------------------------------------------------"
+  confirm
+}
+
+# collect_node_settings - get existing server node configuration
+collect_node_settings() {
+  curl -s -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://$SERVER_HTTP_HOST/api/nodes | jq -c '[ .[] | select(.isserver=="yes") ]' > nodejson.tmp
+  NODE_LEN=$(jq length nodejson.tmp)
+  HAS_INGRESS="no"
+  if [ "$NODE_LEN" -gt 0 ]; then
+      echo "===SERVER NODES==="
+      for i in $(seq 1 $NODE_LEN); do
+          NUM=$(($i-1))
+          echo "  SERVER NODE $NUM:"
+          echo "    network: $(jq -r ".[$NUM].network" ./nodejson.tmp)"
+          echo "      name: $(jq -r ".[$NUM].name" ./nodejson.tmp)"
+          echo "      private ipv4: $(jq -r ".[$NUM].address" ./nodejson.tmp)"
+          echo "      private ipv6: $(jq -r ".[$NUM].address6" ./nodejson.tmp)"
+          echo "      is egress: $(jq -r ".[$NUM].isegressgateway" ./nodejson.tmp)"
+          if [[ $(jq -r ".[$NUM].isegressgateway" ./nodejson.tmp) == "yes" ]]; then
+              echo "          egress range: $(jq -r ".[$NUM].egressgatewayranges" ./nodejson.tmp)"
+          fi
+          echo "      is ingress: $(jq -r ".[$NUM].isingressgateway" ./nodejson.tmp)"
+          if [[ $(jq -r ".[$NUM].isingressgateway" ./nodejson.tmp) == "yes" ]]; then
+              HAS_INGRESS="yes"
+          fi
+          echo "      is relay: $(jq -r ".[$NUM].isrelay" ./nodejson.tmp)"
+          if [[ $(jq -r ".[$NUM].isrelay" ./nodejson.tmp) == "yes" ]]; then
+              HAS_RELAY="yes"
+              echo "          relay addrs: $(jq -r ".[$NUM].relayaddrs" ./nodejson.tmp | tr -d '[]\n"[:space:]')"
+          fi
+          echo "      is failover: $(jq -r ".[$NUM].failover" ./nodejson.tmp)"
+          echo "  ------------"
+      done
+      echo "=================="
+  else
+      echo "no nodes to parse"
+  fi
+
+  echo "Please confirm that the above output matches the server nodes in your Netmaker server."
+  confirm
+
+  if [[ $HAS_INGRESS == "yes" ]]; then
+      echo "WARNING: Your server contains an Ingress Gateway. After upgrading, existing Ext Clients will be lost and must be recreated. Please confirm that you would like to continue."
+      confirm
+  fi
+}
+
+# set_compose - set compose file with proper values
+set_compose() {
+
+  # DEV_TEMP - Temporary instructions for testing
+  sed -i "s/v0.17.1/testing/g" /root/docker-compose.yml
+
+  # RELEASE_REPLACE - Use this once release is ready
+  #sed -i "s/v0.17.1/v0.18.0/g" /root/docker-compose.yml
+  yq ".services.netmaker.environment.SERVER_NAME = \"$SERVER_NAME\"" -i /root/docker-compose.yml
+  yq ".services.netmaker.environment += {\"BROKER_NAME\": \"$BROKER_NAME\"}" -i /root/docker-compose.yml  
+  yq ".services.netmaker.environment += {\"STUN_NAME\": \"$STUN_NAME\"}" -i /root/docker-compose.yml  
+  yq ".services.netmaker.environment += {\"STUN_PORT\": \"3478\"}" -i /root/docker-compose.yml  
+  yq ".services.netmaker.ports += \"3478:3478/udp\"" -i /root/docker-compose.yml
+}
+
+# start_containers - run docker-compose up -d
+start_containers() {
+  docker-compose -f /root/docker-compose.yml up -d
+}
+
+# test_caddy - make sure caddy is working
+test_caddy() {
+  echo "Testing Caddy setup (please be patient, this may take 1-2 minutes)"
+  for i in 1 2 3 4 5 6 7 8
+  do
+  curlresponse=$(curl -vIs https://${SERVER_HTTP_HOST} 2>&1)
+
+  if [[ "$i" == 8 ]]; then
+    echo "    Caddy is having an issue setting up certificates, please investigate (docker logs caddy)"
+    echo "    Exiting..."
+    exit 1
+  elif [[ "$curlresponse" == *"failed to verify the legitimacy of the server"* ]]; then
+    echo "    Certificates not yet configured, retrying..."
+
+  elif [[ "$curlresponse" == *"left intact"* ]]; then
+    echo "    Certificates ok"
+    break
+  else
+    secs=$(($i*5+10))
+    echo "    Issue establishing connection...retrying in $secs seconds..."       
+  fi
+  sleep $secs
+  done
+}
+
+# setup_netclient - installs netclient locally
+setup_netclient() {
+
+# DEV_TEMP - Temporary instructions for testing
+wget https://fileserver.netmaker.org/testing/netclient
+chmod +x netclient
+./netclient install
+
+# RELEASE_REPLACE - Use this once release is ready
+# if [ -f /etc/debian_version ]; then
+#     curl -sL 'https://apt.netmaker.org/gpg.key' | sudo tee /etc/apt/trusted.gpg.d/netclient.asc
+#     curl -sL 'https://apt.netmaker.org/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/netclient.list
+#     sudo apt update
+#     sudo apt install netclient
+# elif [ -f /etc/centos-release ]; then
+#     curl -sL 'https://rpm.netmaker.org/gpg.key' | sudo tee /tmp/gpg.key
+#     curl -sL 'https://rpm.netmaker.org/netclient-repo' | sudo tee /etc/yum.repos.d/netclient.repo
+#     sudo rpm --import /tmp/gpg.key
+#     sudo dnf check-update
+#     sudo dnf install netclient
+# elif [ -f /etc/fedora-release ]; then
+#     curl -sL 'https://rpm.netmaker.org/gpg.key' | sudo tee /tmp/gpg.key
+#     curl -sL 'https://rpm.netmaker.org/netclient-repo' | sudo tee /etc/yum.repos.d/netclient.repo
+#     sudo rpm --import /tmp/gpg.key
+#     sudo dnf check-update
+#     sudo dnf install netclient
+# elif [ -f /etc/redhat-release ]; then
+#     curl -sL 'https://rpm.netmaker.org/gpg.key' | sudo tee /tmp/gpg.key
+#     curl -sL 'https://rpm.netmaker.org/netclient-repo' | sudo tee /etc/yum.repos.d/netclient.repo
+#     sudo rpm --import /tmp/gpg.key
+#     sudo dnf check-update(
+#     sudo dnf install netclient
+# elif [ -f /etc/arch-release ]; then
+#     yay -S netclient
+# else
+# 	echo "OS not supported for automatic install"
+#     exit 1
+# fi
+
+# if [ -z "${install_cmd}" ]; then
+#         echo "OS unsupported for automatic dependency install"
+# 	exit 1
+# fi
+}
+
+# setup_nmctl - pulls nmctl and makes it executable
+setup_nmctl() {
+
+  # DEV_TEMP - Temporary instructions for testing
+  wget https://fileserver.netmaker.org/testing/nmctl
+ 
+  # RELEASE_REPLACE - Use this once release is ready
+  # wget https://github.com/gravitl/netmaker/releases/download/v0.17.1/nmctl
+    chmod +x nmctl
+    echo "using server $SERVER_HTTP_HOST"
+    echo "using master key $MASTER_KEY"
+    ./nmctl context set default --endpoint="https://$SERVER_HTTP_HOST" --master_key="$MASTER_KEY"
+    ./nmctl context use default
+    RESP=$(./nmctl network list)
+    if [[ $RESP == *"unauthorized"* ]]; then
+        echo "Unable to properly configure NMCTL, exiting..."
+        exit 1
+    fi
+}
+
+# join_networks - joins netclient into the networks using old settings
+join_networks() {
+  NODE_LEN=$(jq length nodejson.tmp)
+  HAS_INGRESS="no"
+  if [ "$NODE_LEN" -gt 0 ]; then
+      for i in $(seq 1 $NODE_LEN); do
+          NUM=$(($i-1))
+          NETWORK=$(jq -r ".[$NUM].network" ./nodejson.tmp)
+          echo "  joining network $NETWORK with following settings. Please confirm:"
+          echo "         network: $(jq -r ".[$NUM].network" ./nodejson.tmp)"
+          echo "            name: $(jq -r ".[$NUM].name" ./nodejson.tmp)"
+          echo "    private ipv4: $(jq -r ".[$NUM].address" ./nodejson.tmp)"
+          echo "    private ipv6: $(jq -r ".[$NUM].address6" ./nodejson.tmp)"
+          echo "       is egress: $(jq -r ".[$NUM].isegressgateway" ./nodejson.tmp)"
+          if [[ $(jq -r ".[$NUM].isegressgateway" ./nodejson.tmp) == "yes" ]]; then
+              HAS_EGRESS="yes"
+              echo "          egress range: $(jq -r ".[$NUM].egressgatewayranges" ./nodejson.tmp)"
+          fi
+          echo "      is ingress: $(jq -r ".[$NUM].isingressgateway" ./nodejson.tmp)"
+          if [[ $(jq -r ".[$NUM].isingressgateway" ./nodejson.tmp) == "yes" ]]; then
+              HAS_INGRESS="yes"
+          fi
+          echo "        is relay: $(jq -r ".[$NUM].isrelay" ./nodejson.tmp)"
+          if [[ $(jq -r ".[$NUM].isrelay" ./nodejson.tmp) == "yes" ]]; then
+              HAS_RELAY="yes"
+              RELAY_ADDRS=$(jq -r ".[$NUM].relayaddrs" ./nodejson.tmp | tr -d '[]\n"[:space:]')
+          fi
+          echo "     is failover: $(jq -r ".[$NUM].failover" ./nodejson.tmp)"
+          if [[ $(jq -r ".[$NUM].failover" ./nodejson.tmp) == "yes" ]]; then
+              HAS_FAILOVER="yes"
+          fi
+          echo "  ------------"
+
+          confirm
+          echo "running command: ./nmctl keys create $NETWORK 1"
+          KEY_JSON=$(./nmctl keys create $NETWORK 1)          
+          KEY=$(echo $KEY_JSON | jq -r .accessstring)
+
+          echo "join key created: $KEY"
+
+          NAME=$(jq -r ".[$NUM].name" ./nodejson.tmp)
+          ADDRESS=$(jq -r ".[$NUM].address" ./nodejson.tmp)
+          ADDRESS6=$(jq -r ".[$NUM].address6" ./nodejson.tmp)
+ 
+
+          if [[ ! -z "$ADDRESS6" ]]; then
+            echo "joining with command: netclient join -t $KEY --name=$NAME --address=$ADDRESS --address6=$ADDRESS6
+"
+            confirm
+            netclient join -t $KEY --name=$NAME --address=$ADDRESS --address6=$ADDRESS6
+          else
+            echo "joining with command: netclient join -t $KEY --name=$NAME --address=$ADDRESS"          
+            confirm
+            netclient join -t $KEY --name=$NAME --address=$ADDRESS
+          fi
+          NODE_ID=$(sudo cat /etc/netclient/nodes.yml | yq -r .$NETWORK.commonnode.id)
+          echo "join complete. New node ID: $NODE_ID"
+          if [[ $NUM -eq 0 ]]; then
+            HOST_ID=$(sudo cat /etc/netclient/netclient.yml | yq -r .host.id)
+            echo "For first join, making host a default"
+            echo "Host ID: $HOST_ID"
+            # set as a default host
+            # TODO - this command is not working
+            ./nmctl host update $HOST_ID --default
+          fi
+
+          # create an egress if necessary
+          if [[ $HAS_EGRESS == "yes" ]]; then
+            echo "Egress is currently unimplemented. Wait for 0.18.1"
+          fi
+
+          echo "HAS INGRESS: $HAS_INGRESS"
+          # create an ingress if necessary
+          if [[ $HAS_INGRESS == "yes" ]]; then
+            if [[ $HAS_FAILOVER == "yes" ]]; then
+              echo "creating ingress and failover..."
+              ./nmctl node create_ingress $NETWORK $NODE_ID --failover
+            else
+              echo "creating ingress..."
+              ./nmctl node create_ingress $NETWORK $NODE_ID
+            fi
+          fi
+
+          # relay
+          if [[ $HAS_RELAY == "yes" ]]; then
+            echo "creating relay..."
+            ./nmctl node create_relay $NETWORK $NODE_ID $RELAY_ADDRS
+          fi
+
+      done
+      echo "=================="
+  else
+      echo "no networks to join"
+  fi
+}
+
+
+cat << "EOF"
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+The Netmaker Upgrade Script: Upgrading to v0.18.0 so you don't have to!
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+EOF
+
+set -e 
+
+if [ $(id -u) -ne 0 ]; then
+   echo "This script must be run as root"
+   exit 1
+fi
+
+echo "...installing dependencies for script"
+install_dependencies
+
+echo "...confirming version is correct"
+check_version
+
+echo "...collecting necessary server settings"
+collect_server_settings
+
+echo "...setup nmctl"
+setup_nmctl
+
+echo "...retrieving current server node settings"
+collect_node_settings
+
+echo "...backing up docker compose to docker-compose.yml.backup"
+cp /root/docker-compose.yml /root/docker-compose.yml.backup
+
+echo "...setting docker-compose values"
+set_compose
+
+echo "...starting containers"
+start_containers
+
+wait_seconds 3
+
+echo "..testing Caddy proxy"
+test_caddy
+
+echo "..testing Netmaker health"
+# TODO, implement health check
+# netmaker_health_check
+# wait_seconds 2
+
+echo "...setting up netclient (this may take a minute, be patient)"
+setup_netclient
+wait_seconds 2
+
+echo "...join networks"
+join_networks
+
+echo "-----------------------------------------------------------------"
+echo "-----------------------------------------------------------------"
+echo "Netmaker setup is now complete. You are ready to begin using Netmaker."
+echo "Visit dashboard.$SERVER_NAME to log in"
+echo "-----------------------------------------------------------------"
+echo "-----------------------------------------------------------------"

+ 0 - 49
servercfg/serverconf.go

@@ -76,15 +76,7 @@ func GetServerConfig() config.ServerConfig {
 	cfg.ClientID = authInfo[1]
 	cfg.ClientSecret = authInfo[2]
 	cfg.FrontendURL = GetFrontendURL()
-	if GetRce() {
-		cfg.RCE = "on"
-	} else {
-		cfg.RCE = "off"
-	}
 	cfg.Telemetry = Telemetry()
-	cfg.ManageIPTables = ManageIPTables()
-	services := strings.Join(GetPortForwardServiceList(), ",")
-	cfg.PortForwardServices = services
 	cfg.Server = GetServer()
 	cfg.Verbosity = GetVerbosity()
 	cfg.IsEE = "no"
@@ -379,18 +371,6 @@ func Telemetry() string {
 	return telemetry
 }
 
-// ManageIPTables - checks if iptables should be manipulated on host
-func ManageIPTables() string {
-	manage := "on"
-	if os.Getenv("MANAGE_IPTABLES") == "off" {
-		manage = "off"
-	}
-	if config.Config.Server.ManageIPTables == "off" {
-		manage = "off"
-	}
-	return manage
-}
-
 // GetServer - gets the server name
 func GetServer() string {
 	server := ""
@@ -528,19 +508,6 @@ func GetPlatform() string {
 	return platform
 }
 
-// GetIPForwardServiceList - get the list of services that the server should be forwarding
-func GetPortForwardServiceList() []string {
-	//services := "mq,dns,ssh"
-	services := ""
-	if os.Getenv("PORT_FORWARD_SERVICES") != "" {
-		services = os.Getenv("PORT_FORWARD_SERVICES")
-	} else if config.Config.Server.PortForwardServices != "" {
-		services = config.Config.Server.PortForwardServices
-	}
-	serviceSlice := strings.Split(services, ",")
-	return serviceSlice
-}
-
 // GetSQLConn - get the sql connection string
 func GetSQLConn() string {
 	sqlconn := "http://"
@@ -552,17 +519,6 @@ func GetSQLConn() string {
 	return sqlconn
 }
 
-// IsHostNetwork - checks if running on host network
-func IsHostNetwork() bool {
-	ishost := false
-	if os.Getenv("HOST_NETWORK") == "on" {
-		ishost = true
-	} else if config.Config.Server.HostNetwork == "on" {
-		ishost = true
-	}
-	return ishost
-}
-
 // GetNodeID - gets the node id
 func GetNodeID() string {
 	var id string
@@ -640,11 +596,6 @@ func GetAzureTenant() string {
 	return azureTenant
 }
 
-// GetRce - sees if Rce is enabled, off by default
-func GetRce() bool {
-	return os.Getenv("RCE") == "on" || config.Config.Server.RCE == "on"
-}
-
 // GetMQServerPort - get mq port for server
 func GetMQServerPort() string {
 	port := "1883" //default

+ 0 - 136
serverctl/iptables.go

@@ -1,136 +0,0 @@
-package serverctl
-
-import (
-	"errors"
-	"net"
-	"os"
-	"os/exec"
-	"strings"
-	"time"
-
-	"github.com/gravitl/netmaker/logger"
-	"github.com/gravitl/netmaker/netclient/ncutils"
-	"github.com/gravitl/netmaker/servercfg"
-)
-
-const netmakerProcessName = "netmaker"
-
-// InitIPTables - intializes the server iptables
-func InitIPTables(force bool) error {
-	_, err := exec.LookPath("iptables")
-	if err != nil {
-		return err
-	}
-	err = setForwardPolicy()
-	if err != nil {
-		logger.Log(0, "error setting iptables forward policy: "+err.Error())
-	}
-
-	err = portForwardServices(force)
-	if err != nil {
-		return err
-	}
-	if isContainerized() && servercfg.IsHostNetwork() {
-		err = setHostCoreDNSMapping()
-	}
-	return err
-}
-
-// set up port forwarding for services listed in config
-func portForwardServices(force bool) error {
-	var err error
-	services := servercfg.GetPortForwardServiceList()
-	if len(services) == 0 || services[0] == "" {
-		return nil
-	}
-	for _, service := range services {
-		switch service {
-		case "mq":
-			err = iptablesPortForward("mq", servercfg.GetMQServerPort(), servercfg.GetMQServerPort(), false, force)
-		case "dns":
-			err = iptablesPortForward("coredns", "53", "53", false, force)
-		case "ssh":
-			err = iptablesPortForward("netmaker", "22", "22", false, force)
-		default:
-			params := strings.Split(service, ":")
-			if len(params) == 3 {
-				err = iptablesPortForward(params[0], params[1], params[2], true, force)
-			}
-		}
-		if err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-// determine if process is running in container
-func isContainerized() bool {
-	fileBytes, err := os.ReadFile("/proc/1/sched")
-	if err != nil {
-		logger.Log(1, "error determining containerization: "+err.Error())
-		return false
-	}
-	fileString := string(fileBytes)
-	return strings.Contains(fileString, netmakerProcessName)
-}
-
-// make sure host allows forwarding
-func setForwardPolicy() error {
-	logger.Log(2, "setting iptables forward policy")
-	_, err := ncutils.RunCmd("iptables --policy FORWARD ACCEPT", false)
-	return err
-}
-
-// port forward from an entry, can contain a dns name for lookup
-func iptablesPortForward(entry string, inport string, outport string, isIP, force bool) error {
-
-	var address string
-	if !isIP {
-	out:
-		for i := 1; i < 4; i++ {
-			ips, err := net.LookupIP(entry)
-			if err != nil && i > 2 {
-				return err
-			}
-			for _, ip := range ips {
-				if ipv4 := ip.To4(); ipv4 != nil {
-					address = ipv4.String()
-				}
-			}
-			if address != "" {
-				break out
-			}
-			time.Sleep(time.Second)
-		}
-	} else {
-		address = entry
-	}
-	if address == "" {
-		return errors.New("could not locate ip for " + entry)
-	}
-
-	if output, err := ncutils.RunCmd("iptables -t nat -C PREROUTING -p tcp --dport "+inport+" -j DNAT --to-destination "+address+":"+outport, false); output != "" || err != nil || force {
-		_, err := ncutils.RunCmd("iptables -t nat -A PREROUTING -p tcp --dport "+inport+" -j DNAT --to-destination "+address+":"+outport, false)
-		if err != nil {
-			return err
-		}
-		_, err = ncutils.RunCmd("iptables -t nat -A PREROUTING -p udp --dport "+inport+" -j DNAT --to-destination "+address+":"+outport, false)
-		if err != nil {
-			return err
-		}
-		_, err = ncutils.RunCmd("iptables -t nat -A POSTROUTING -j MASQUERADE", false)
-		return err
-	} else {
-		logger.Log(3, "mq forwarding is already set... skipping")
-	}
-	return nil
-}
-
-// if running in host networking mode, run iptables to map to CoreDNS container
-func setHostCoreDNSMapping() error {
-	logger.Log(1, "forwarding dns traffic on host from netmaker interfaces to 53053")
-	ncutils.RunCmd("iptables -t nat -A PREROUTING -i nm-+ -p tcp --match tcp --dport 53 --jump REDIRECT --to-ports 53053", true)
-	_, err := ncutils.RunCmd("iptables -t nat -A PREROUTING -i nm-+ -p udp --match udp --dport 53 --jump REDIRECT --to-ports 53053", true)
-	return err
-}

+ 1 - 1
serverctl/serverctl.go

@@ -85,7 +85,7 @@ func setNetworkDefaults() error {
 			}
 		} else {
 			network.SetDefaults()
-			_, _, _, _, _, _, err = logic.UpdateNetwork(&network, &network)
+			_, _, _, _, _, err = logic.UpdateNetwork(&network, &network)
 			if err != nil {
 				logger.Log(0, "could not set defaults on network", network.NetID)
 			}

+ 0 - 26
swagger.yaml

@@ -105,12 +105,6 @@ definitions:
             nodeid:
                 type: string
                 x-go-name: NodeID
-            postdown:
-                type: string
-                x-go-name: PostDown
-            postup:
-                type: string
-                x-go-name: PostUp
             ranges:
                 items:
                     type: string
@@ -270,12 +264,6 @@ definitions:
                 format: int32
                 type: integer
                 x-go-name: DefaultMTU
-            defaultpostdown:
-                type: string
-                x-go-name: DefaultPostDown
-            defaultpostup:
-                type: string
-                x-go-name: DefaultPostUp
             defaultudpholepunch:
                 type: string
                 x-go-name: DefaultUDPHolePunch
@@ -291,9 +279,6 @@ definitions:
             ispointtosite:
                 type: string
                 x-go-name: IsPointToSite
-            localrange:
-                type: string
-                x-go-name: LocalRange
             netid:
                 type: string
                 x-go-name: NetID
@@ -432,9 +417,6 @@ definitions:
                 format: int32
                 type: integer
                 x-go-name: LocalListenPort
-            localrange:
-                type: string
-                x-go-name: LocalRange
             macaddress:
                 type: string
                 x-go-name: MacAddress
@@ -460,12 +442,6 @@ definitions:
                 format: int32
                 type: integer
                 x-go-name: PersistentKeepalive
-            postdown:
-                type: string
-                x-go-name: PostDown
-            postup:
-                type: string
-                x-go-name: PostUp
             publickey:
                 type: string
                 x-go-name: PublicKey
@@ -644,8 +620,6 @@ definitions:
                 type: string
             PublicIPService:
                 type: string
-            RCE:
-                type: string
             RestBackend:
                 type: string
             SQLConn:

+ 0 - 3
test/network_test.go.bak

@@ -467,17 +467,14 @@ func TestUpdateNetwork(t *testing.T) {
 	})
 	t.Run("UpdatePostUP", func(t *testing.T) {
 		type Network struct {
-			DefaultPostUp string
 		}
 		var network Network
-		network.DefaultPostUp = "sudo wg add-conf wc-netmaker /etc/wireguard/peers/conf"
 		response, err := api(t, network, http.MethodPut, baseURL+"/api/networks/skynet", "secretkey")
 		assert.Nil(t, err, err)
 		assert.Equal(t, http.StatusOK, response.StatusCode)
 		defer response.Body.Close()
 		err = json.NewDecoder(response.Body).Decode(&returnedNetwork)
 		assert.Nil(t, err, err)
-		assert.Equal(t, network.DefaultPostUp, returnedNetwork.DefaultPostUp)
 	})
 	t.Run("UpdatePostDown", func(t *testing.T) {
 		type Network struct {