merge conflicts resolved

This commit is contained in:
Abhishek Kondur
2023-02-07 14:24:39 +04:00
83 changed files with 1616 additions and 3603 deletions

View File

@@ -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)
}

View File

@@ -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)
}

View File

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

View File

@@ -41,19 +41,13 @@ var networkCreateCmd = &cobra.Command{
if defaultACL { if defaultACL {
network.DefaultACL = "yes" network.DefaultACL = "yes"
} }
if pointToSite {
network.IsPointToSite = "yes"
}
network.DefaultInterface = defaultInterface network.DefaultInterface = defaultInterface
network.DefaultListenPort = int32(defaultListenPort) network.DefaultListenPort = int32(defaultListenPort)
network.NodeLimit = int32(nodeLimit) network.NodeLimit = int32(nodeLimit)
network.DefaultPostUp = defaultPostUp
network.DefaultPostDown = defaultPostDown
network.DefaultKeepalive = int32(defaultKeepalive) network.DefaultKeepalive = int32(defaultKeepalive)
if allowManualSignUp { if allowManualSignUp {
network.AllowManualSignUp = "yes" network.AllowManualSignUp = "yes"
} }
network.LocalRange = localRange
network.DefaultExtClientDNS = defaultExtClientDNS network.DefaultExtClientDNS = defaultExtClientDNS
network.DefaultMTU = int32(defaultMTU) 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(&udpHolePunch, "udp_hole_punch", false, "Enable UDP Hole Punching ?")
networkCreateCmd.Flags().BoolVar(&localNetwork, "local", false, "Is the network local (LAN) ?") 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(&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(&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().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(&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") networkCreateCmd.Flags().IntVar(&nodeLimit, "node_limit", 999999999, "Maximum number of nodes that can be associated with this network")

View File

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

View File

@@ -44,19 +44,13 @@ var networkUpdateCmd = &cobra.Command{
if defaultACL { if defaultACL {
network.DefaultACL = "yes" network.DefaultACL = "yes"
} }
if pointToSite {
network.IsPointToSite = "yes"
}
network.DefaultInterface = defaultInterface network.DefaultInterface = defaultInterface
network.DefaultListenPort = int32(defaultListenPort) network.DefaultListenPort = int32(defaultListenPort)
network.NodeLimit = int32(nodeLimit) network.NodeLimit = int32(nodeLimit)
network.DefaultPostUp = defaultPostUp
network.DefaultPostDown = defaultPostDown
network.DefaultKeepalive = int32(defaultKeepalive) network.DefaultKeepalive = int32(defaultKeepalive)
if allowManualSignUp { if allowManualSignUp {
network.AllowManualSignUp = "yes" network.AllowManualSignUp = "yes"
} }
network.LocalRange = localRange
network.DefaultExtClientDNS = defaultExtClientDNS network.DefaultExtClientDNS = defaultExtClientDNS
network.DefaultMTU = int32(defaultMTU) 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(&udpHolePunch, "udp_hole_punch", false, "Enable UDP Hole Punching ?")
networkUpdateCmd.Flags().BoolVar(&localNetwork, "local", false, "Is the network local (LAN) ?") 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(&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(&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().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(&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") networkUpdateCmd.Flags().IntVar(&nodeLimit, "node_limit", 0, "Maximum number of nodes that can be associated with this network")

View File

@@ -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)
}

View File

@@ -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)
}

View File

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

View File

@@ -1,6 +1,7 @@
package functions package functions
import ( import (
"fmt"
"net/http" "net/http"
"github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/models"
@@ -31,3 +32,16 @@ func UpdateHostNetworks(hostID string, networks []string) *hostNetworksUpdatePay
Networks: networks, 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)
}

View File

@@ -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) 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 // CreateEgress - turn a node into an egress
func CreateEgress(networkName, nodeID string, payload *models.EgressGatewayRequest) *models.ApiNode { 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) return request[models.ApiNode](http.MethodPost, fmt.Sprintf("/api/nodes/%s/%s/creategateway", networkName, nodeID), payload)

View File

@@ -4,15 +4,6 @@ services:
netmaker: netmaker:
container_name: netmaker container_name: netmaker
image: gravitl/netmaker:v0.17.1-ee 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 restart: always
volumes: volumes:
- dnsconfig:/root/config/dnsconfig - dnsconfig:/root/config/dnsconfig
@@ -35,10 +26,7 @@ services:
MQ_HOST: "mq" MQ_HOST: "mq"
MQ_PORT: "443" MQ_PORT: "443"
MQ_SERVER_PORT: "1883" MQ_SERVER_PORT: "1883"
HOST_NETWORK: "off"
VERBOSITY: "1" VERBOSITY: "1"
MANAGE_IPTABLES: "on"
PORT_FORWARD_SERVICES: "dns"
METRICS_EXPORTER: "on" METRICS_EXPORTER: "on"
LICENSE_KEY: "YOUR_LICENSE_KEY" LICENSE_KEY: "YOUR_LICENSE_KEY"
NETMAKER_ACCOUNT_ID: "YOUR_ACCOUNT_ID" NETMAKER_ACCOUNT_ID: "YOUR_ACCOUNT_ID"

View File

@@ -4,15 +4,6 @@ services:
netmaker: # The Primary Server for running Netmaker netmaker: # The Primary Server for running Netmaker
container_name: netmaker container_name: netmaker
image: gravitl/netmaker:v0.17.1 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 restart: always
volumes: # Volume mounts necessary for sql, coredns, and mqtt volumes: # Volume mounts necessary for sql, coredns, and mqtt
- dnsconfig:/root/config/dnsconfig - dnsconfig:/root/config/dnsconfig
@@ -26,11 +17,9 @@ services:
COREDNS_ADDR: "SERVER_PUBLIC_IP" # Address of the CoreDNS server. Defaults to SERVER_HOST 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. 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. 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. 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. 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. 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. 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 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. 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_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_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) 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 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 # this section is for OAuth
AUTH_PROVIDER: "" # "<azure-ad|github|google|oidc>" AUTH_PROVIDER: "" # "<azure-ad|github|google|oidc>"
CLIENT_ID: "" # "<client id of your oauth provider>" CLIENT_ID: "" # "<client id of your oauth provider>"

View File

@@ -4,15 +4,6 @@ services:
netmaker: netmaker:
container_name: netmaker container_name: netmaker
image: gravitl/netmaker:v0.17.1 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 restart: always
volumes: volumes:
- dnsconfig:/root/config/dnsconfig - dnsconfig:/root/config/dnsconfig
@@ -27,7 +18,6 @@ services:
DNS_MODE: "on" DNS_MODE: "on"
SERVER_HTTP_HOST: "api.NETMAKER_BASE_DOMAIN" SERVER_HTTP_HOST: "api.NETMAKER_BASE_DOMAIN"
API_PORT: "8081" API_PORT: "8081"
CLIENT_MODE: "on"
MASTER_KEY: "REPLACE_MASTER_KEY" MASTER_KEY: "REPLACE_MASTER_KEY"
CORS_ALLOWED_ORIGIN: "*" CORS_ALLOWED_ORIGIN: "*"
DISPLAY_KEYS: "on" DISPLAY_KEYS: "on"
@@ -36,7 +26,6 @@ services:
MQ_HOST: "mq" MQ_HOST: "mq"
MQ_PORT: "443" MQ_PORT: "443"
MQ_SERVER_PORT: "1883" MQ_SERVER_PORT: "1883"
HOST_NETWORK: "off"
VERBOSITY: "1" VERBOSITY: "1"
MANAGE_IPTABLES: "on" MANAGE_IPTABLES: "on"
PORT_FORWARD_SERVICES: "dns" PORT_FORWARD_SERVICES: "dns"

View File

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

View File

@@ -160,7 +160,7 @@ func createDNS(w http.ResponseWriter, r *http.Request) {
return return
} }
entry, err = CreateDNS(entry) entry, err = logic.CreateDNS(entry)
if err != nil { if err != nil {
logger.Log(0, r.Header.Get("user"), logger.Log(0, r.Header.Get("user"),
fmt.Sprintf("Failed to create DNS entry %+v: %v", entry, err)) 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.") 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 // GetDNSEntry - gets a DNS entry
func GetDNSEntry(domain string, network string) (models.DNSEntry, error) { func GetDNSEntry(domain string, network string) (models.DNSEntry, error) {
var entry models.DNSEntry var entry models.DNSEntry

View File

@@ -1,35 +1,45 @@
package controller package controller
import ( import (
"net"
"os" "os"
"testing" "testing"
"github.com/google/uuid"
"github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/logic" "github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/models"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
) )
var dnsHost models.Host
func TestGetAllDNS(t *testing.T) { func TestGetAllDNS(t *testing.T) {
database.InitializeDatabase() database.InitializeDatabase()
deleteAllDNS(t) deleteAllDNS(t)
deleteAllNetworks() deleteAllNetworks()
createNet() createNet()
createHost()
t.Run("NoEntries", func(t *testing.T) { t.Run("NoEntries", func(t *testing.T) {
entries, err := logic.GetAllDNS() entries, err := logic.GetAllDNS()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, []models.DNSEntry(nil), entries) assert.Equal(t, []models.DNSEntry(nil), entries)
}) })
t.Run("OneEntry", func(t *testing.T) { t.Run("OneEntry", func(t *testing.T) {
entry := models.DNSEntry{"10.0.0.3", "", "newhost", "skynet"} entry := models.DNSEntry{
CreateDNS(entry) "10.0.0.3", "", "newhost", "skynet",
}
_, err := logic.CreateDNS(entry)
assert.Nil(t, err)
entries, err := logic.GetAllDNS() entries, err := logic.GetAllDNS()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(entries)) assert.Equal(t, 1, len(entries))
}) })
t.Run("MultipleEntry", func(t *testing.T) { t.Run("MultipleEntry", func(t *testing.T) {
entry := models.DNSEntry{"10.0.0.7", "", "anotherhost", "skynet"} entry := models.DNSEntry{"10.0.0.7", "", "anotherhost", "skynet"}
CreateDNS(entry) _, err := logic.CreateDNS(entry)
assert.Nil(t, err)
entries, err := logic.GetAllDNS() entries, err := logic.GetAllDNS()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 2, len(entries)) assert.Equal(t, 2, len(entries))
@@ -41,22 +51,42 @@ func TestGetNodeDNS(t *testing.T) {
deleteAllDNS(t) deleteAllDNS(t)
deleteAllNetworks() deleteAllNetworks()
createNet() createNet()
createHost()
t.Run("NoNodes", func(t *testing.T) { t.Run("NoNodes", func(t *testing.T) {
dns, err := logic.GetNodeDNS("skynet") dns, err := logic.GetNodeDNS("skynet")
assert.EqualError(t, err, "could not find any records") assert.EqualError(t, err, "could not find any records")
assert.Equal(t, []models.DNSEntry(nil), dns) assert.Equal(t, []models.DNSEntry(nil), dns)
}) })
t.Run("NodeExists", func(t *testing.T) { 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"} createHost()
err := logic.CreateNode(&createnode) _, 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) assert.Nil(t, err)
dns, err := logic.GetNodeDNS("skynet") dns, err := logic.GetNodeDNS("skynet")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "10.0.0.1", dns[0].Address) assert.Equal(t, "10.0.0.1", dns[0].Address)
}) })
t.Run("MultipleNodes", func(t *testing.T) { 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"} _, ipnet, _ := net.ParseCIDR("10.100.100.3/32")
err := logic.CreateNode(createnode) 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) assert.Nil(t, err)
dns, err := logic.GetNodeDNS("skynet") dns, err := logic.GetNodeDNS("skynet")
assert.Nil(t, err) assert.Nil(t, err)
@@ -85,15 +115,17 @@ func TestGetCustomDNS(t *testing.T) {
assert.Equal(t, 0, len(dns)) assert.Equal(t, 0, len(dns))
}) })
t.Run("EntryExist", func(t *testing.T) { t.Run("EntryExist", func(t *testing.T) {
entry := models.DNSEntry{"10.0.0.3", "", "newhost", "skynet"} entry := models.DNSEntry{"10.0.0.3", "", "custom1", "skynet"}
CreateDNS(entry) _, err := logic.CreateDNS(entry)
assert.Nil(t, err)
dns, err := logic.GetCustomDNS("skynet") dns, err := logic.GetCustomDNS("skynet")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(dns)) assert.Equal(t, 1, len(dns))
}) })
t.Run("MultipleEntries", func(t *testing.T) { t.Run("MultipleEntries", func(t *testing.T) {
entry := models.DNSEntry{"10.0.0.4", "", "host4", "skynet"} entry := models.DNSEntry{"10.0.0.4", "", "host4", "skynet"}
CreateDNS(entry) _, err := logic.CreateDNS(entry)
assert.Nil(t, err)
dns, err := logic.GetCustomDNS("skynet") dns, err := logic.GetCustomDNS("skynet")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 2, len(dns)) assert.Equal(t, 2, len(dns))
@@ -112,7 +144,7 @@ func TestGetDNSEntryNum(t *testing.T) {
}) })
t.Run("NodeExists", func(t *testing.T) { t.Run("NodeExists", func(t *testing.T) {
entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"} entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"}
_, err := CreateDNS(entry) _, err := logic.CreateDNS(entry)
assert.Nil(t, err) assert.Nil(t, err)
num, err := logic.GetDNSEntryNum("newhost", "skynet") num, err := logic.GetDNSEntryNum("newhost", "skynet")
assert.Nil(t, err) assert.Nil(t, err)
@@ -131,7 +163,7 @@ func TestGetDNS(t *testing.T) {
}) })
t.Run("CustomDNSExists", func(t *testing.T) { t.Run("CustomDNSExists", func(t *testing.T) {
entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"} entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"}
_, err := CreateDNS(entry) _, err := logic.CreateDNS(entry)
assert.Nil(t, err) assert.Nil(t, err)
dns, err := logic.GetDNS("skynet") dns, err := logic.GetDNS("skynet")
t.Log(dns) t.Log(dns)
@@ -151,7 +183,7 @@ func TestGetDNS(t *testing.T) {
}) })
t.Run("NodeAndCustomDNS", func(t *testing.T) { t.Run("NodeAndCustomDNS", func(t *testing.T) {
entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"} entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"}
_, err := CreateDNS(entry) _, err := logic.CreateDNS(entry)
assert.Nil(t, err) assert.Nil(t, err)
dns, err := logic.GetDNS("skynet") dns, err := logic.GetDNS("skynet")
t.Log(dns) t.Log(dns)
@@ -169,7 +201,7 @@ func TestCreateDNS(t *testing.T) {
deleteAllNetworks() deleteAllNetworks()
createNet() createNet()
entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"} entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"}
dns, err := CreateDNS(entry) dns, err := logic.CreateDNS(entry)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "newhost", dns.Name) assert.Equal(t, "newhost", dns.Name)
} }
@@ -204,12 +236,13 @@ func TestSetDNS(t *testing.T) {
assert.False(t, info.IsDir()) assert.False(t, info.IsDir())
content, err := os.ReadFile("./config/dnsconfig/netmaker.hosts") content, err := os.ReadFile("./config/dnsconfig/netmaker.hosts")
assert.Nil(t, err) 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) { t.Run("EntryExists", func(t *testing.T) {
entry := models.DNSEntry{"10.0.0.3", "", "newhost", "skynet"} entry := models.DNSEntry{"10.0.0.3", "", "newhost", "skynet"}
CreateDNS(entry) _, err := logic.CreateDNS(entry)
err := logic.SetDNS() assert.Nil(t, err)
err = logic.SetDNS()
assert.Nil(t, err) assert.Nil(t, err)
info, err := os.Stat("./config/dnsconfig/netmaker.hosts") info, err := os.Stat("./config/dnsconfig/netmaker.hosts")
assert.Nil(t, err) assert.Nil(t, err)
@@ -228,7 +261,7 @@ func TestGetDNSEntry(t *testing.T) {
createNet() createNet()
createTestNode() createTestNode()
entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"} entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"}
CreateDNS(entry) _, _ = logic.CreateDNS(entry)
t.Run("wrong net", func(t *testing.T) { t.Run("wrong net", func(t *testing.T) {
entry, err := GetDNSEntry("newhost", "w286 Toronto Street South, Uxbridge, ONirecat") entry, err := GetDNSEntry("newhost", "w286 Toronto Street South, Uxbridge, ONirecat")
assert.EqualError(t, err, "no result found") 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) { func TestDeleteDNS(t *testing.T) {
database.InitializeDatabase() database.InitializeDatabase()
deleteAllDNS(t) deleteAllDNS(t)
deleteAllNetworks() deleteAllNetworks()
createNet() createNet()
entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"} entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"}
CreateDNS(entry) _, _ = logic.CreateDNS(entry)
t.Run("EntryExists", func(t *testing.T) { t.Run("EntryExists", func(t *testing.T) {
err := logic.DeleteDNS("newhost", "skynet") err := logic.DeleteDNS("newhost", "skynet")
assert.Nil(t, err) assert.Nil(t, err)
@@ -351,8 +357,8 @@ func TestValidateDNSUpdate(t *testing.T) {
}) })
t.Run("NameUnique", func(t *testing.T) { t.Run("NameUnique", func(t *testing.T) {
change := models.DNSEntry{"10.0.0.2", "", "myhost", "wirecat"} change := models.DNSEntry{"10.0.0.2", "", "myhost", "wirecat"}
CreateDNS(entry) _, _ = logic.CreateDNS(entry)
CreateDNS(change) _, _ = logic.CreateDNS(change)
err := logic.ValidateDNSUpdate(change, entry) err := logic.ValidateDNSUpdate(change, entry)
assert.NotNil(t, err) assert.NotNil(t, err)
assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'name_unique' tag") 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) { t.Run("NameUnique", func(t *testing.T) {
entry := models.DNSEntry{"10.0.0.2", "", "myhost", "skynet"} entry := models.DNSEntry{"10.0.0.2", "", "myhost", "skynet"}
_, _ = CreateDNS(entry) _, _ = logic.CreateDNS(entry)
err := logic.ValidateDNSCreate(entry) err := logic.ValidateDNSCreate(entry)
assert.NotNil(t, err) assert.NotNil(t, err)
assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'name_unique' tag") 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) { func deleteAllDNS(t *testing.T) {
dns, err := logic.GetAllDNS() dns, err := logic.GetAllDNS()
assert.Nil(t, err) assert.Nil(t, err)

View File

@@ -12,12 +12,9 @@ import (
"github.com/gravitl/netmaker/logic" "github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/mq" "github.com/gravitl/netmaker/mq"
"golang.org/x/crypto/bcrypt"
) )
type hostNetworksUpdatePayload struct {
Networks []string `json:"networks"`
}
func hostHandlers(r *mux.Router) { func hostHandlers(r *mux.Router) {
r.HandleFunc("/api/hosts", logic.SecurityCheck(true, http.HandlerFunc(getHosts))).Methods(http.MethodGet) 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) 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}/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(createHostRelay))).Methods(http.MethodPost)
r.HandleFunc("/api/hosts/{hostid}/relay", logic.SecurityCheck(false, http.HandlerFunc(deleteHostRelay))).Methods(http.MethodDelete) 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 // swagger:route GET /api/hosts hosts getHosts
@@ -99,6 +97,10 @@ func updateHost(w http.ResponseWriter, r *http.Request) {
if updateRelay { if updateRelay {
logic.UpdateHostRelay(currHost.ID.String(), currHost.RelayedHosts, newHost.RelayedHosts) logic.UpdateHostRelay(currHost.ID.String(), currHost.RelayedHosts, newHost.RelayedHosts)
} }
<<<<<<< HEAD
=======
>>>>>>> f4851937c1746475fdac99e9c562623128ba16b1
// publish host update through MQ // publish host update through MQ
if err := mq.HostUpdate(&models.HostUpdate{ if err := mq.HostUpdate(&models.HostUpdate{
Action: models.UpdateHost, Action: models.UpdateHost,
@@ -139,7 +141,33 @@ func deleteHost(w http.ResponseWriter, r *http.Request) {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return 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 { if err = logic.RemoveHost(currHost); err != nil {
logger.Log(0, r.Header.Get("user"), "failed to delete a host:", err.Error()) logger.Log(0, r.Header.Get("user"), "failed to delete a host:", err.Error())
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) 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)) logger.Log(2, r.Header.Get("user"), fmt.Sprintf("removed host %s from network %s", currHost.Name, network))
w.WriteHeader(http.StatusOK) 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
controllers/migrate.go Normal file
View File

@@ -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)
}

View File

@@ -185,13 +185,7 @@ func updateNetwork(w http.ResponseWriter, r *http.Request) {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return return
} }
rangeupdate4, rangeupdate6, holepunchupdate, groupsDelta, userDelta, err := logic.UpdateNetwork(&network, &newNetwork)
if !servercfg.GetRce() {
newNetwork.DefaultPostDown = network.DefaultPostDown
newNetwork.DefaultPostUp = network.DefaultPostUp
}
rangeupdate4, rangeupdate6, localrangeupdate, holepunchupdate, groupsDelta, userDelta, err := logic.UpdateNetwork(&network, &newNetwork)
if err != nil { if err != nil {
logger.Log(0, r.Header.Get("user"), "failed to update network: ", logger.Log(0, r.Header.Get("user"), "failed to update network: ",
err.Error()) err.Error())
@@ -237,17 +231,7 @@ func updateNetwork(w http.ResponseWriter, r *http.Request) {
return return
} }
} }
if localrangeupdate { if rangeupdate4 || rangeupdate6 || holepunchupdate {
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 {
nodes, err := logic.GetNetworkNodes(network.NetID) nodes, err := logic.GetNetworkNodes(network.NetID)
if err != nil { if err != nil {
logger.Log(0, r.Header.Get("user"), logger.Log(0, r.Header.Get("user"),

View File

@@ -4,10 +4,12 @@ import (
"os" "os"
"testing" "testing"
"github.com/google/uuid"
"github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/logic" "github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/models"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
) )
type NetworkValidationTestCase struct { type NetworkValidationTestCase struct {
@@ -16,6 +18,8 @@ type NetworkValidationTestCase struct {
errMessage string errMessage string
} }
var netHost models.Host
func TestCreateNetwork(t *testing.T) { func TestCreateNetwork(t *testing.T) {
initialize() initialize()
deleteAllNetworks() deleteAllNetworks()
@@ -271,14 +275,6 @@ func TestValidateNetwork(t *testing.T) {
}, },
errMessage: "Field validation for 'DefaultKeepalive' failed on the 'max' tag", 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 { for _, tc := range cases {
t.Run(tc.testname, func(t *testing.T) { t.Run(tc.testname, func(t *testing.T) {
@@ -305,11 +301,12 @@ func TestIpv6Network(t *testing.T) {
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, network.AddressRange6, "fde6:be04:fa5e:d076::/64") 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"} node1 := createNodeWithParams("skynet6", "")
nodeErr := logic.CreateNode(&node1) createNetHost()
nodeErr := logic.AssociateNodeToHost(node1, &netHost)
t.Run("Test node on network IPv6", func(t *testing.T) { t.Run("Test node on network IPv6", func(t *testing.T) {
assert.Nil(t, nodeErr) 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) 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)
}

View File

@@ -4,7 +4,6 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"io"
"net/http" "net/http"
"strings" "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}", 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(true, true, "node", http.HandlerFunc(getNode))).Methods(http.MethodGet)
r.HandleFunc("/api/nodes/{network}/{nodeid}", authorize(false, true, "node", http.HandlerFunc(updateNode))).Methods(http.MethodPut) r.HandleFunc("/api/nodes/{network}/{nodeid}", authorize(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}", 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}/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) 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) logic.ReturnErrorResponse(w, r, errorResponse)
return return
} }
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
} }
} }
@@ -524,7 +524,7 @@ func createNode(w http.ResponseWriter, r *http.Request) {
} }
if !logic.IsVersionComptatible(data.Host.Version) { 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")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return return
} }
@@ -550,6 +550,7 @@ func createNode(w http.ResponseWriter, r *http.Request) {
logic.ReturnErrorResponse(w, r, errorResponse) logic.ReturnErrorResponse(w, r, errorResponse)
return return
} }
logic.DecrimentKey(networkName, data.Key)
user, err := pro.GetNetworkUser(networkName, promodels.NetworkUserID(keyName)) user, err := pro.GetNetworkUser(networkName, promodels.NetworkUserID(keyName))
if err == nil { if err == nil {
if user.ID != "" { if user.ID != "" {
@@ -577,6 +578,9 @@ func createNode(w http.ResponseWriter, r *http.Request) {
server := servercfg.GetServerInfo() server := servercfg.GetServerInfo()
server.TrafficKey = key server.TrafficKey = key
data.Node.Server = servercfg.GetServer() data.Node.Server = servercfg.GetServer()
if !logic.HostExists(&data.Host) {
logic.CheckHostPorts(&data.Host)
}
if err := logic.CreateHost(&data.Host); err != nil { if err := logic.CreateHost(&data.Host); err != nil {
if errors.Is(err, logic.ErrHostExists) { if errors.Is(err, logic.ErrHostExists) {
logger.Log(3, "host exists .. no need to create") 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")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return 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 { } else {
logger.Log(0, "error creating host", err.Error()) logger.Log(0, "error creating host", err.Error())
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) 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")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
data.Host.HostPass = "" // client should not change password after join
// concealing hash
response := models.NodeJoinResponse{ response := models.NodeJoinResponse{
Node: data.Node, Node: data.Node,
ServerConfig: server, ServerConfig: server,
@@ -660,32 +673,33 @@ func createNode(w http.ResponseWriter, r *http.Request) {
// Responses: // Responses:
// 200: nodeResponse // 200: nodeResponse
func createEgressGateway(w http.ResponseWriter, r *http.Request) { func createEgressGateway(w http.ResponseWriter, r *http.Request) {
var gateway models.EgressGatewayRequest logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("currently unimplemented"), "internal"))
var params = mux.Vars(r) // var gateway models.EgressGatewayRequest
w.Header().Set("Content-Type", "application/json") // var params = mux.Vars(r)
err := json.NewDecoder(r.Body).Decode(&gateway) // w.Header().Set("Content-Type", "application/json")
if err != nil { // err := json.NewDecoder(r.Body).Decode(&gateway)
logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error()) // if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) // logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error())
return // logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
} // return
gateway.NetID = params["network"] // }
gateway.NodeID = params["nodeid"] // gateway.NetID = params["network"]
node, err := logic.CreateEgressGateway(gateway) // gateway.NodeID = params["nodeid"]
if err != nil { // node, err := logic.CreateEgressGateway(gateway)
logger.Log(0, r.Header.Get("user"), // if err != nil {
fmt.Sprintf("failed to create egress gateway on node [%s] on network [%s]: %v", // logger.Log(0, r.Header.Get("user"),
gateway.NodeID, gateway.NetID, err)) // fmt.Sprintf("failed to create egress gateway on node [%s] on network [%s]: %v",
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) // gateway.NodeID, gateway.NetID, err))
return // 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) // apiNode := node.ConvertToAPINode()
w.WriteHeader(http.StatusOK) // logger.Log(1, r.Header.Get("user"), "created egress gateway on node", gateway.NodeID, "on network", gateway.NetID)
json.NewEncoder(w).Encode(apiNode) // w.WriteHeader(http.StatusOK)
// json.NewEncoder(w).Encode(apiNode)
runUpdates(&node, true) //
// runUpdates(&node, true)
} }
// swagger:route DELETE /api/nodes/{network}/{nodeid}/deletegateway nodes deleteEgressGateway // swagger:route DELETE /api/nodes/{network}/{nodeid}/deletegateway nodes deleteEgressGateway
@@ -700,25 +714,26 @@ func createEgressGateway(w http.ResponseWriter, r *http.Request) {
// Responses: // Responses:
// 200: nodeResponse // 200: nodeResponse
func deleteEgressGateway(w http.ResponseWriter, r *http.Request) { func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("currently unimplemented"), "internal"))
var params = mux.Vars(r) //w.Header().Set("Content-Type", "application/json")
nodeid := params["nodeid"] // var params = mux.Vars(r)
netid := params["network"] // nodeid := params["nodeid"]
node, err := logic.DeleteEgressGateway(netid, nodeid) // netid := params["network"]
if err != nil { // node, err := logic.DeleteEgressGateway(netid, nodeid)
logger.Log(0, r.Header.Get("user"), // if err != nil {
fmt.Sprintf("failed to delete egress gateway on node [%s] on network [%s]: %v", // logger.Log(0, r.Header.Get("user"),
nodeid, netid, err)) // fmt.Sprintf("failed to delete egress gateway on node [%s] on network [%s]: %v",
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) // nodeid, netid, err))
return // 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) // apiNode := node.ConvertToAPINode()
w.WriteHeader(http.StatusOK) // logger.Log(1, r.Header.Get("user"), "deleted egress gateway on node", nodeid, "on network", netid)
json.NewEncoder(w).Encode(apiNode) // w.WriteHeader(http.StatusOK)
// json.NewEncoder(w).Encode(apiNode)
runUpdates(&node, true) //
// runUpdates(&node, true)
} }
// == INGRESS == // == INGRESS ==
@@ -807,51 +822,6 @@ func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
runUpdates(&node, true) 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 // swagger:route PUT /api/nodes/{network}/{nodeid} nodes updateNode
// //
// Update an individual node. // 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()) { if currentNode.IsRelayed && (currentNode.Address.String() != newNode.Address.String() || currentNode.Address6.String() != newNode.Address6.String()) {
relayedUpdate = true relayedUpdate = true
} }
if !servercfg.GetRce() {
newNode.PostDown = currentNode.PostDown
newNode.PostUp = currentNode.PostUp
}
ifaceDelta := logic.IfaceDelta(&currentNode, newNode) ifaceDelta := logic.IfaceDelta(&currentNode, newNode)
if ifaceDelta && servercfg.Is_EE { 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")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return return
} }
if r.Header.Get("ismaster") != "yes" { if r.Header.Get("ismaster") != "yes" {
username := r.Header.Get("user") username := r.Header.Get("user")
if username != "" && !doesUserOwnNode(username, params["network"], nodeid) { 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.") logic.ReturnSuccessResponse(w, r, nodeid+" deleted.")
logger.Log(1, r.Header.Get("user"), "Deleted node", nodeid, "from network", params["network"]) 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) runUpdates(&node, false)
} }
go func() { // notify of peer change go func() { // notify of peer change

View File

@@ -1,16 +1,22 @@
package controller package controller
import ( import (
"net"
"testing" "testing"
"github.com/google/uuid"
"github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/logic" "github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/logic/acls" "github.com/gravitl/netmaker/logic/acls"
"github.com/gravitl/netmaker/logic/acls/nodeacls" "github.com/gravitl/netmaker/logic/acls/nodeacls"
"github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/models"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
) )
var nonLinuxHost models.Host
var linuxHost models.Host
func TestCreateEgressGateway(t *testing.T) { func TestCreateEgressGateway(t *testing.T) {
var gateway models.EgressGatewayRequest var gateway models.EgressGatewayRequest
gateway.Interface = "eth0" gateway.Interface = "eth0"
@@ -21,45 +27,39 @@ func TestCreateEgressGateway(t *testing.T) {
createNet() createNet()
t.Run("NoNodes", func(t *testing.T) { t.Run("NoNodes", func(t *testing.T) {
node, err := logic.CreateEgressGateway(gateway) 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") assert.EqualError(t, err, "could not find any records")
}) })
t.Run("Non-linux node", func(t *testing.T) { 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"} createnode := createNodeWithParams("", "")
err := logic.CreateNode(&createnode) createNodeHosts()
createnode.HostID = nonLinuxHost.ID
err := logic.AssociateNodeToHost(createnode, &nonLinuxHost)
assert.Nil(t, err) assert.Nil(t, err)
gateway.NodeID = createnode.ID gateway.NodeID = createnode.ID.String()
node, err := logic.CreateEgressGateway(gateway) 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") assert.EqualError(t, err, "windows is unsupported for egress gateways")
}) })
t.Run("Success-Nat-Enabled", func(t *testing.T) { t.Run("Success-Nat-Enabled", func(t *testing.T) {
deleteAllNodes() deleteAllNodes()
testnode := createTestNode() testnode := createTestNode()
gateway.NodeID = testnode.ID gateway.NodeID = testnode.ID.String()
gateway.NatEnabled = "yes" gateway.NatEnabled = "yes"
node, err := logic.CreateEgressGateway(gateway) node, err := logic.CreateEgressGateway(gateway)
t.Log(node.EgressGatewayNatEnabled) t.Log(node.EgressGatewayNatEnabled)
t.Log(node.PostUp)
t.Log(node.PostDown)
assert.Nil(t, err) 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) { t.Run("Success-Nat-Disabled", func(t *testing.T) {
deleteAllNodes() deleteAllNodes()
testnode := createTestNode() testnode := createTestNode()
gateway.NodeID = testnode.ID gateway.NodeID = testnode.ID.String()
gateway.NatEnabled = "no" gateway.NatEnabled = "no"
node, err := logic.CreateEgressGateway(gateway) node, err := logic.CreateEgressGateway(gateway)
t.Log(node.EgressGatewayNatEnabled) t.Log(node.EgressGatewayNatEnabled)
t.Log(node.PostUp)
t.Log(node.PostDown)
assert.Nil(t, err) 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) { t.Run("Success", func(t *testing.T) {
var gateway models.EgressGatewayRequest var gateway models.EgressGatewayRequest
@@ -68,14 +68,12 @@ func TestCreateEgressGateway(t *testing.T) {
gateway.NetID = "skynet" gateway.NetID = "skynet"
deleteAllNodes() deleteAllNodes()
testnode := createTestNode() testnode := createTestNode()
gateway.NodeID = testnode.ID gateway.NodeID = testnode.ID.String()
node, err := logic.CreateEgressGateway(gateway) node, err := logic.CreateEgressGateway(gateway)
t.Log(node) t.Log(node)
assert.Nil(t, err) assert.Nil(t, err)
assert.Contains(t, node.PostUp, "-j MASQUERADE") assert.Equal(t, true, node.IsEgressGateway)
assert.Contains(t, node.PostDown, "-j MASQUERADE")
assert.Equal(t, "yes", node.IsEgressGateway)
assert.Equal(t, gateway.Ranges, node.EgressGatewayRanges) assert.Equal(t, gateway.Ranges, node.EgressGatewayRanges)
}) })
@@ -89,31 +87,27 @@ func TestDeleteEgressGateway(t *testing.T) {
gateway.Interface = "eth0" gateway.Interface = "eth0"
gateway.Ranges = []string{"10.100.100.0/24"} gateway.Ranges = []string{"10.100.100.0/24"}
gateway.NetID = "skynet" gateway.NetID = "skynet"
gateway.NodeID = testnode.ID gateway.NodeID = testnode.ID.String()
t.Run("Success", func(t *testing.T) { t.Run("Success", func(t *testing.T) {
node, err := logic.CreateEgressGateway(gateway) node, err := logic.CreateEgressGateway(gateway)
assert.Nil(t, err) 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) assert.Equal(t, []string{"10.100.100.0/24"}, node.EgressGatewayRanges)
node, err = logic.DeleteEgressGateway(gateway.NetID, gateway.NodeID) node, err = logic.DeleteEgressGateway(gateway.NetID, gateway.NodeID)
assert.Nil(t, err) 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, []string([]string{}), node.EgressGatewayRanges)
assert.Equal(t, "", node.PostUp)
assert.Equal(t, "", node.PostDown)
}) })
t.Run("NotGateway", func(t *testing.T) { t.Run("NotGateway", func(t *testing.T) {
node, err := logic.DeleteEgressGateway(gateway.NetID, gateway.NodeID) node, err := logic.DeleteEgressGateway(gateway.NetID, gateway.NodeID)
assert.Nil(t, err) 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, []string([]string{}), node.EgressGatewayRanges)
assert.Equal(t, "", node.PostUp)
assert.Equal(t, "", node.PostDown)
}) })
t.Run("BadNode", func(t *testing.T) { t.Run("BadNode", func(t *testing.T) {
node, err := logic.DeleteEgressGateway(gateway.NetID, "01:02:03") node, err := logic.DeleteEgressGateway(gateway.NetID, "01:02:03")
assert.EqualError(t, err, "no result found") assert.EqualError(t, err, "no result found")
assert.Equal(t, models.LegacyNode{}, node) assert.Equal(t, models.Node{}, node)
deleteAllNodes() 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) { func TestValidateEgressGateway(t *testing.T) {
var gateway models.EgressGatewayRequest var gateway models.EgressGatewayRequest
t.Run("EmptyRange", func(t *testing.T) { t.Run("EmptyRange", func(t *testing.T) {
@@ -181,66 +159,73 @@ func TestValidateEgressGateway(t *testing.T) {
func TestNodeACLs(t *testing.T) { func TestNodeACLs(t *testing.T) {
deleteAllNodes() 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"} node1 := createNodeWithParams("", "10.0.0.50/32")
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"} node2 := createNodeWithParams("", "10.0.0.100/32")
logic.CreateNode(&node1) logic.AssociateNodeToHost(node1, &linuxHost)
logic.CreateNode(&node2) logic.AssociateNodeToHost(node2, &linuxHost)
t.Run("acls not present", func(t *testing.T) { t.Run("acls not present", func(t *testing.T) {
currentACL, err := nodeacls.FetchAllACLs(nodeacls.NetworkID(node1.Network)) currentACL, err := nodeacls.FetchAllACLs(nodeacls.NetworkID(node1.Network))
assert.Nil(t, err) assert.Nil(t, err)
assert.NotNil(t, currentACL) 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.Nil(t, err)
assert.NotNil(t, node1ACL) 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) { 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.Nil(t, err)
assert.NotNil(t, node1ACL) 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.Nil(t, err)
assert.NotNil(t, node2ACL) 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) { 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.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) { 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.Nil(t, err)
assert.NotNil(t, node1ACL) 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.Nil(t, err)
assert.NotNil(t, node2ACL) 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.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(node1.ID.String())][acls.AclID(node2.ID.String())])
assert.Equal(t, acls.NotAllowed, currentACL[acls.AclID(node2.ID)][acls.AclID(node1.ID)]) assert.Equal(t, acls.NotAllowed, currentACL[acls.AclID(node2.ID.String())][acls.AclID(node1.ID.String())])
currentACL.Save(acls.ContainerID(node1.Network)) currentACL.Save(acls.ContainerID(node1.Network))
}) })
t.Run("node acls correct after add new node not allowed", func(t *testing.T) { 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"} node3 := createNodeWithParams("", "10.0.0.100/32")
logic.CreateNode(&node3) createNodeHosts()
var currentACL, err = nodeacls.FetchAllACLs(nodeacls.NetworkID(node3.Network)) 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.Nil(t, err)
assert.NotNil(t, currentACL) assert.NotNil(t, currentACL)
assert.Equal(t, acls.NotPresent, currentACL[acls.AclID(node1.ID)][acls.AclID(node3.ID)]) 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), acls.NotAllowed) nodeACL, err := nodeacls.CreateNodeACL(nodeacls.NetworkID(node3.Network), nodeacls.NodeID(node3.ID.String()), acls.NotAllowed)
assert.Nil(t, err) 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)) currentACL, err = nodeacls.FetchAllACLs(nodeacls.NetworkID(node3.Network))
assert.Nil(t, err) 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(node1.ID.String())][acls.AclID(node3.ID.String())])
assert.Equal(t, acls.NotAllowed, currentACL[acls.AclID(node2.ID)][acls.AclID(node3.ID)]) 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) { 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.Nil(t, err)
assert.NotNil(t, retNetworkACL) 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() deleteAllNodes()
} }
@@ -249,8 +234,51 @@ func deleteAllNodes() {
database.DeleteAllRecords(database.NODES_TABLE_NAME) database.DeleteAllRecords(database.NODES_TABLE_NAME)
} }
func createTestNode() *models.LegacyNode { func createTestNode() *models.Node {
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"} createNodeHosts()
logic.CreateNode(&createnode) 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 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)
}

View File

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

View File

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

6
go.mod
View File

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

9
go.sum
View File

@@ -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.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 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 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 h1:A0HD94yMdt4usgxBjoEceNeE0XMJ027euoHAzsPqBQs=
github.com/guumaster/tablewriter v0.0.10/go.mod h1:p4FRFhyfo0UD9ZLmMRbbJooTUsxo6b80qZTERVDWrH8= github.com/guumaster/tablewriter v0.0.10/go.mod h1:p4FRFhyfo0UD9ZLmMRbbJooTUsxo6b80qZTERVDWrH8=
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= 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/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.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 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.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/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.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 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 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 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.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.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 h1:BSnJgAfHzEp7o8PYJ7YfwAVHhqu7BYUTggcn/LGlUWY=
github.com/rqlite/gorqlite v0.0.0-20210514125552-08ff1e76b22f/go.mod h1:UW/gxgQwSePTvL1KA8QEHsXeYHP4xkoXgbDdN781p34= 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 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.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0/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/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 h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= 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= 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-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-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-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.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 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View File

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

View File

@@ -74,14 +74,27 @@ func GetNodeDNS(network string) ([]models.DNSEntry, error) {
} }
for _, value := range collection { for _, value := range collection {
var entry models.DNSEntry
var node models.Node var node models.Node
if err = json.Unmarshal([]byte(value), &node); err != nil { if err = json.Unmarshal([]byte(value), &node); err != nil {
continue continue
} }
if err = json.Unmarshal([]byte(value), &entry); node.Network == network && err == nil { if node.Network != network {
dns = append(dns, entry) 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 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 { _ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
_, err := GetParentNetwork(change.Network) _, err := GetParentNetwork(change.Network)
if err != nil {
logger.Log(0, err.Error())
}
return err == nil return err == nil
}) })
@@ -245,3 +255,20 @@ func DeleteDNS(domain string, network string) error {
err = database.DeleteRecord(database.DNS_TABLE_NAME, key) err = database.DeleteRecord(database.DNS_TABLE_NAME, key)
return err 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
}

View File

@@ -138,12 +138,6 @@ func CreateExtClient(extclient *models.ExtClient) error {
return err return err
} }
extclient.Address = newAddress.String() 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 return err
} }
extclient.Address6 = addr6.String() extclient.Address6 = addr6.String()
extclientInternalAddr6, err := UniqueAddress6(extclient.Network, false)
if err != nil {
return err
}
extclient.InternalIPAddr6 = extclientInternalAddr6.String()
} }
} }

View File

@@ -4,7 +4,6 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"strings"
"time" "time"
"github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/database"
@@ -48,62 +47,6 @@ func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, erro
node.EgressGatewayRanges = gateway.Ranges node.EgressGatewayRanges = gateway.Ranges
node.EgressGatewayNatEnabled = models.ParseBool(gateway.NatEnabled) node.EgressGatewayNatEnabled = models.ParseBool(gateway.NatEnabled)
node.EgressGatewayRequest = gateway // store entire request for use when preserving the egress gateway 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() node.SetLastModified()
nodeData, err := json.Marshal(&node) nodeData, err := json.Marshal(&node)
if err != nil { if err != nil {
@@ -136,39 +79,9 @@ func DeleteEgressGateway(network, nodeid string) (models.Node, error) {
if err != nil { if err != nil {
return models.Node{}, err return models.Node{}, err
} }
host, err := GetHost(node.HostID.String())
if err != nil {
return models.Node{}, err
}
node.IsEgressGateway = false node.IsEgressGateway = false
node.EgressGatewayRanges = []string{} node.EgressGatewayRanges = []string{}
node.EgressGatewayRequest = models.EgressGatewayRequest{} // remove preserved request as the egress gateway is gone 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() node.SetLastModified()
data, err := json.Marshal(&node) data, err := json.Marshal(&node)
@@ -184,7 +97,6 @@ func DeleteEgressGateway(network, nodeid string) (models.Node, error) {
// CreateIngressGateway - creates an ingress gateway // CreateIngressGateway - creates an ingress gateway
func CreateIngressGateway(netid string, nodeid string, failover bool) (models.Node, error) { func CreateIngressGateway(netid string, nodeid string, failover bool) (models.Node, error) {
var postUpCmd, postDownCmd string
node, err := GetNodeByID(nodeid) node, err := GetNodeByID(nodeid)
if err != nil { if err != nil {
return models.Node{}, err return models.Node{}, err
@@ -193,6 +105,9 @@ func CreateIngressGateway(netid string, nodeid string, failover bool) (models.No
if err != nil { if err != nil {
return models.Node{}, err 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 { if host.FirewallInUse == models.FIREWALL_NONE {
return models.Node{}, errors.New("firewall is not supported for ingress gateways") 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 return models.Node{}, err
} }
node.IsIngressGateway = true node.IsIngressGateway = true
cidrs := []string{}
cidrs = append(cidrs, network.AddressRange)
cidrs = append(cidrs, network.AddressRange6)
node.IngressGatewayRange = network.AddressRange node.IngressGatewayRange = network.AddressRange
node.IngressGatewayRange6 = network.AddressRange6 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.SetLastModified()
node.PostUp = postUpCmd
node.PostDown = postDownCmd
if failover && servercfg.Is_EE { if failover && servercfg.Is_EE {
node.Failover = true node.Failover = true
} }
@@ -274,10 +160,6 @@ func DeleteIngressGateway(networkName string, nodeid string) (models.Node, bool,
node.IngressGatewayRange = "" node.IngressGatewayRange = ""
node.Failover = false 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) //logger.Log(3, "deleting ingress gateway firewall in use is '", host.FirewallInUse, "' and isEgressGateway is", node.IsEgressGateway)
if node.EgressGatewayRequest.NodeID != "" { if node.EgressGatewayRequest.NodeID != "" {
_, err := CreateEgressGateway(node.EgressGatewayRequest) _, err := CreateEgressGateway(node.EgressGatewayRequest)
@@ -315,128 +197,3 @@ func DeleteGatewayExtClients(gatewayID string, networkName string) error {
} }
return nil 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
logic/host_test.go Normal file
View File

@@ -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)
})
}

View File

@@ -20,6 +20,11 @@ var (
ErrInvalidHostID error = errors.New("invalid host id") ErrInvalidHostID error = errors.New("invalid host id")
) )
const (
maxPort = 1<<16 - 1
minPort = 1025
)
// GetAllHosts - returns all hosts in flat list or error // GetAllHosts - returns all hosts in flat list or error
func GetAllHosts() ([]models.Host, error) { func GetAllHosts() ([]models.Host, error) {
currHostMap, err := GetHostsMap() currHostMap, err := GetHostsMap()
@@ -117,10 +122,6 @@ func UpdateHost(newHost, currentHost *models.Host) {
newHost.Name = currentHost.Name newHost.Name = currentHost.Name
} }
if newHost.LocalRange.String() != currentHost.LocalRange.String() {
newHost.LocalRange = currentHost.LocalRange
}
if newHost.MTU == 0 { if newHost.MTU == 0 {
newHost.MTU = currentHost.MTU newHost.MTU = currentHost.MTU
} }
@@ -132,6 +133,42 @@ func UpdateHost(newHost, currentHost *models.Host) {
if newHost.ProxyListenPort == 0 { if newHost.ProxyListenPort == 0 {
newHost.ProxyListenPort = currentHost.ProxyListenPort 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* // 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 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
}
}

View File

@@ -130,7 +130,7 @@ func VerifyUserToken(tokenString string) (username string, networks []string, is
} }
// VerifyToken - [nodes] Only // 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{} claims := &models.Claims{}
// this may be a stupid way of serving up a master key // this may be a stupid way of serving up a master key

View File

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

View File

@@ -237,12 +237,12 @@ func IsIPUnique(network string, ip string, tableName string, isIpv6 bool) bool {
continue continue
} }
if isIpv6 { if isIpv6 {
if (extClient.Address6 == ip || extClient.InternalIPAddr6 == ip) && extClient.Network == network { if (extClient.Address6 == ip) && extClient.Network == network {
return false return false
} }
} else { } else {
if (extClient.Address == ip || extClient.InternalIPAddr == ip) && extClient.Network == network { if (extClient.Address == ip) && extClient.Network == network {
return false 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") 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 // UpdateNetworkLocalAddresses - updates network localaddresses
func UpdateNetworkLocalAddresses(networkName string) error { 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 // 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 { 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 { if newNetwork.NetID == currentNetwork.NetID {
hasrangeupdate4 := newNetwork.AddressRange != currentNetwork.AddressRange hasrangeupdate4 := newNetwork.AddressRange != currentNetwork.AddressRange
hasrangeupdate6 := newNetwork.AddressRange6 != currentNetwork.AddressRange6 hasrangeupdate6 := newNetwork.AddressRange6 != currentNetwork.AddressRange6
localrangeupdate := newNetwork.LocalRange != currentNetwork.LocalRange
hasholepunchupdate := newNetwork.DefaultUDPHolePunch != currentNetwork.DefaultUDPHolePunch hasholepunchupdate := newNetwork.DefaultUDPHolePunch != currentNetwork.DefaultUDPHolePunch
groupDelta := append(StringDifference(newNetwork.ProSettings.AllowedGroups, currentNetwork.ProSettings.AllowedGroups), groupDelta := append(StringDifference(newNetwork.ProSettings.AllowedGroups, currentNetwork.ProSettings.AllowedGroups),
StringDifference(currentNetwork.ProSettings.AllowedGroups, newNetwork.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)...) StringDifference(currentNetwork.ProSettings.AllowedUsers, newNetwork.ProSettings.AllowedUsers)...)
data, err := json.Marshal(newNetwork) data, err := json.Marshal(newNetwork)
if err != nil { if err != nil {
return false, false, false, false, nil, nil, err return false, false, false, nil, nil, err
} }
newNetwork.SetNetworkLastModified() newNetwork.SetNetworkLastModified()
err = database.Insert(newNetwork.NetID, string(data), database.NETWORKS_TABLE_NAME) 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 // 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 // GetNetwork - gets a network from database

View File

@@ -50,7 +50,7 @@ func GetNetworkNodes(network string) ([]models.Node, error) {
func UpdateNode(currentNode *models.Node, newNode *models.Node) error { func UpdateNode(currentNode *models.Node, newNode *models.Node) error {
if newNode.Address.IP.String() != currentNode.Address.IP.String() { if newNode.Address.IP.String() != currentNode.Address.IP.String() {
if network, err := GetParentNetwork(newNode.Network); err == nil { 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) 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 var node models.Node
// ignore legacy nodes in database // ignore legacy nodes in database
if err := json.Unmarshal([]byte(value), &node); err != nil { 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 continue
} }
// add node to our array // add node to our array
@@ -239,7 +239,6 @@ func SetNodeDefaults(node *models.Node) {
if err == nil { if err == nil {
node.NetworkRange6 = *cidr node.NetworkRange6 = *cidr
} }
node.ExpirationDateTime = time.Now().Add(models.TEN_YEARS_IN_SECONDS)
if node.DefaultACL == "" { if node.DefaultACL == "" {
node.DefaultACL = parentNetwork.DefaultACL node.DefaultACL = parentNetwork.DefaultACL
@@ -248,49 +247,10 @@ func SetNodeDefaults(node *models.Node) {
if node.PersistentKeepalive == 0 { if node.PersistentKeepalive == 0 {
node.PersistentKeepalive = time.Second * time.Duration(parentNetwork.DefaultKeepalive) node.PersistentKeepalive = time.Second * time.Duration(parentNetwork.DefaultKeepalive)
} }
if node.PostUp == "" { node.SetLastModified()
postup := parentNetwork.DefaultPostUp node.SetLastCheckIn()
node.PostUp = postup node.SetDefaultConnected()
} node.SetExpirationDateTime()
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 ------
} }
// GetRecordKey - get record key // GetRecordKey - get record key
@@ -302,30 +262,6 @@ func GetRecordKey(id string, network string) (string, error) {
return id + "###" + network, nil 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 // GetNodesByAddress - gets a node by mac address
func GetNodesByAddress(network string, addresses []string) ([]models.Node, error) { func GetNodesByAddress(network string, addresses []string) ([]models.Node, error) {
var nodes []models.Node var nodes []models.Node

View File

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

View File

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

View File

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

View File

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

View File

@@ -5,7 +5,6 @@ import (
crand "crypto/rand" crand "crypto/rand"
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"fmt"
"math/big" "math/big"
"math/rand" "math/rand"
"net" "net"
@@ -15,8 +14,6 @@ import (
"github.com/c-robinson/iplib" "github.com/c-robinson/iplib"
"github.com/gravitl/netmaker/database" "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 // 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 // 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) var _, currentCIDR, cidrErr = net.ParseCIDR(cidr)
if cidrErr != nil { if cidrErr != nil {
return false return false
} }
var addrParts = strings.Split(address, ".") return currentCIDR.Contains(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)
} }
// SetNetworkNodesLastModified - sets the network nodes last modified // SetNetworkNodesLastModified - sets the network nodes last modified
@@ -113,26 +96,6 @@ func RandomString(length int) string {
return string(b) 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 // StringSliceContains - sees if a string slice contains a string element
func StringSliceContains(slice []string, item string) bool { func StringSliceContains(slice []string, item string) bool {
for _, s := range slice { for _, s := range slice {
@@ -143,8 +106,6 @@ func StringSliceContains(slice []string, item string) bool {
return false return false
} }
// == private ==
// NormalCIDR - returns the first address of CIDR // NormalCIDR - returns the first address of CIDR
func NormalizeCIDR(address string) (string, error) { func NormalizeCIDR(address string) (string, error) {
ip, IPNet, err := net.ParseCIDR(address) ip, IPNet, err := net.ParseCIDR(address)
@@ -161,23 +122,6 @@ func NormalizeCIDR(address string) (string, error) {
return IPNet.String(), nil 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`. // StringDifference - returns the elements in `a` that aren't in `b`.
func StringDifference(a, b []string) []string { func StringDifference(a, b []string) []string {
mb := make(map[string]struct{}, len(b)) mb := make(map[string]struct{}, len(b))
@@ -206,3 +150,5 @@ func CheckIfFileExists(filePath string) bool {
func RemoveStringSlice(slice []string, i int) []string { func RemoveStringSlice(slice []string, i int) []string {
return append(slice[:i], slice[i+1:]...) return append(slice[:i], slice[i+1:]...)
} }
// == private ==

View File

@@ -25,6 +25,7 @@ var (
// CheckZombies - checks if new node has same macaddress as existing node // CheckZombies - checks if new node has same macaddress as existing node
// if so, existing node is added to zombie node quarantine list // 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) { func CheckZombies(newnode *models.Node, mac net.HardwareAddr) {
nodes, err := GetNetworkNodes(newnode.Network) nodes, err := GetNetworkNodes(newnode.Network)
if err != nil { if err != nil {
@@ -32,12 +33,11 @@ func CheckZombies(newnode *models.Node, mac net.HardwareAddr) {
return return
} }
for _, node := range nodes { for _, node := range nodes {
host, err := GetHost(node.HostID.String()) if node.ID == newnode.ID {
if err != nil { //skip self
// should we delete the node if host not found ??
continue 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") logger.Log(0, "adding ", node.ID.String(), " to zombie list")
newZombie <- node.ID 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 // 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") logger.Log(2, "Zombie management started")
InitializeZombies() InitializeZombies()
for { for {
@@ -80,11 +80,13 @@ func ManageZombies(ctx context.Context) {
zombies = append(zombies[:i], zombies[i+1:]...) zombies = append(zombies[:i], zombies[i+1:]...)
continue 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 { if err := DeleteNode(&node, true); err != nil {
logger.Log(1, "error deleting zombie node", zombies[i].String(), err.Error()) logger.Log(1, "error deleting zombie node", zombies[i].String(), err.Error())
continue continue
} }
node.Action = models.NODE_DELETE
peerUpdate <- &node
logger.Log(1, "deleting zombie node", node.ID.String()) logger.Log(1, "deleting zombie node", node.ID.String())
zombies = append(zombies[:i], zombies[i+1:]...) zombies = append(zombies[:i], zombies[i+1:]...)
} }

16
main.go
View File

@@ -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.") 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() { if servercfg.IsDNSMode() {
err := functions.SetDNSDir() err := functions.SetDNSDir()
@@ -191,7 +185,15 @@ func runMessageQueue(wg *sync.WaitGroup) {
mq.SetupMQTT() mq.SetupMQTT()
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
go mq.Keepalive(ctx) 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) go logic.PurgePendingNodes(ctx)
quit := make(chan os.Signal, 1) quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGTERM, os.Interrupt) signal.Notify(quit, syscall.SIGTERM, os.Interrupt)

111
metrics/metrics.go Normal file
View File

@@ -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
}

View File

@@ -10,5 +10,4 @@ type AccessToken struct {
type ClientConfig struct { type ClientConfig struct {
Network string `json:"network"` Network string `json:"network"`
Key string `json:"key"` Key string `json:"key"`
LocalRange string `json:"localrange"`
} }

View File

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

View File

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

View File

@@ -14,6 +14,4 @@ type ExtClient struct {
LastModified int64 `json:"lastmodified" bson:"lastmodified"` LastModified int64 `json:"lastmodified" bson:"lastmodified"`
Enabled bool `json:"enabled" bson:"enabled"` Enabled bool `json:"enabled" bson:"enabled"`
OwnerID string `json:"ownerid" bson:"ownerid"` 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"`
} }

View File

@@ -24,8 +24,6 @@ type Host struct {
Interface string `json:"interface" yaml:"interface"` Interface string `json:"interface" yaml:"interface"`
Debug bool `json:"debug" yaml:"debug"` Debug bool `json:"debug" yaml:"debug"`
ListenPort int `json:"listenport" yaml:"listenport"` 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"` PublicListenPort int `json:"public_listen_port" yaml:"public_listen_port"`
ProxyListenPort int `json:"proxy_listen_port" yaml:"proxy_listen_port"` ProxyListenPort int `json:"proxy_listen_port" yaml:"proxy_listen_port"`
MTU int `json:"mtu" yaml:"mtu"` MTU int `json:"mtu" yaml:"mtu"`

8
models/migrate.go Normal file
View File

@@ -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
}

View File

@@ -1,7 +1,8 @@
package models package models
import ( import (
proxy_models "github.com/gravitl/netclient/nmproxy/models" "net"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes" "golang.zx2c4.com/wireguard/wgctrl/wgtypes"
) )
@@ -13,18 +14,41 @@ type PeerUpdate struct {
Peers []wgtypes.PeerConfig `json:"peers" bson:"peers" yaml:"peers"` Peers []wgtypes.PeerConfig `json:"peers" bson:"peers" yaml:"peers"`
DNS string `json:"dns" bson:"dns" yaml:"dns"` DNS string `json:"dns" bson:"dns" yaml:"dns"`
PeerIDs PeerMap `json:"peerids" bson:"peerids" yaml:"peerids"` PeerIDs PeerMap `json:"peerids" bson:"peerids" yaml:"peerids"`
ProxyUpdate proxy_models.ProxyManagerPayload `json:"proxy_update" bson:"proxy_update" yaml:"proxy_update"` ProxyUpdate ProxyManagerPayload `json:"proxy_update" bson:"proxy_update" yaml:"proxy_update"`
} }
// HostPeerUpdate - struct for host peer updates // HostPeerUpdate - struct for host peer updates
type HostPeerUpdate struct { type HostPeerUpdate struct {
Host Host `json:"host" bson:"host" yaml:"host"` Host Host `json:"host" bson:"host" yaml:"host"`
Server string `json:"server" bson:"server" yaml:"server"`
ServerVersion string `json:"serverversion" bson:"serverversion" yaml:"serverversion"` ServerVersion string `json:"serverversion" bson:"serverversion" yaml:"serverversion"`
ServerAddrs []ServerAddr `json:"serveraddrs" bson:"serveraddrs" yaml:"serveraddrs"` ServerAddrs []ServerAddr `json:"serveraddrs" bson:"serveraddrs" yaml:"serveraddrs"`
Network map[string]NetworkInfo `json:"network" bson:"network" yaml:"network"` Network map[string]NetworkInfo `json:"network" bson:"network" yaml:"network"`
Peers []wgtypes.PeerConfig `json:"peers" bson:"peers" yaml:"peers"` Peers []wgtypes.PeerConfig `json:"peers" bson:"peers" yaml:"peers"`
PeerIDs HostPeerMap `json:"peerids" bson:"peerids" yaml:"peerids"` PeerIDs HostPeerMap `json:"peerids" bson:"peerids" yaml:"peerids"`
ProxyUpdate proxy_models.ProxyManagerPayload `json:"proxy_update" bson:"proxy_update" yaml:"proxy_update"` 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 // NetworkInfo - struct for network info

View File

@@ -17,7 +17,6 @@ type Network struct {
DefaultInterface string `json:"defaultinterface" bson:"defaultinterface" validate:"min=1,max=15"` 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"` DefaultListenPort int32 `json:"defaultlistenport,omitempty" bson:"defaultlistenport,omitempty" validate:"omitempty,min=1024,max=65535"`
NodeLimit int32 `json:"nodelimit" bson:"nodelimit"` NodeLimit int32 `json:"nodelimit" bson:"nodelimit"`
DefaultPostUp string `json:"defaultpostup" bson:"defaultpostup"`
DefaultPostDown string `json:"defaultpostdown" bson:"defaultpostdown"` DefaultPostDown string `json:"defaultpostdown" bson:"defaultpostdown"`
DefaultKeepalive int32 `json:"defaultkeepalive" bson:"defaultkeepalive" validate:"omitempty,max=1000"` DefaultKeepalive int32 `json:"defaultkeepalive" bson:"defaultkeepalive" validate:"omitempty,max=1000"`
AccessKeys []AccessKey `json:"accesskeys" bson:"accesskeys"` AccessKeys []AccessKey `json:"accesskeys" bson:"accesskeys"`
@@ -25,8 +24,6 @@ type Network struct {
IsLocal string `json:"islocal" bson:"islocal" validate:"checkyesorno"` IsLocal string `json:"islocal" bson:"islocal" validate:"checkyesorno"`
IsIPv4 string `json:"isipv4" bson:"isipv4" validate:"checkyesorno"` IsIPv4 string `json:"isipv4" bson:"isipv4" validate:"checkyesorno"`
IsIPv6 string `json:"isipv6" bson:"isipv6" 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"` DefaultUDPHolePunch string `json:"defaultudpholepunch" bson:"defaultudpholepunch" validate:"checkyesorno"`
DefaultExtClientDNS string `json:"defaultextclientdns" bson:"defaultextclientdns"` DefaultExtClientDNS string `json:"defaultextclientdns" bson:"defaultextclientdns"`
DefaultMTU int32 `json:"defaultmtu" bson:"defaultmtu"` DefaultMTU int32 `json:"defaultmtu" bson:"defaultmtu"`
@@ -57,9 +54,6 @@ func (network *Network) SetDefaults() {
if network.IsLocal == "" { if network.IsLocal == "" {
network.IsLocal = "no" network.IsLocal = "no"
} }
if network.IsPointToSite == "" {
network.IsPointToSite = "no"
}
if network.DefaultInterface == "" { if network.DefaultInterface == "" {
if len(network.NetID) < 13 { if len(network.NetID) < 13 {
network.DefaultInterface = "nm-" + network.NetID network.DefaultInterface = "nm-" + network.NetID

View File

@@ -13,13 +13,4 @@ package models
// assert.Equal(t, "NetID is not editable", err.Error()) // assert.Equal(t, "NetID is not editable", err.Error())
// t.Log(err, Range, local) // 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)
// })
//} //}

View File

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

68
models/proxy.go Normal file
View File

@@ -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
}

View File

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

View File

@@ -29,14 +29,14 @@ func Ping(client mqtt.Client, msg mqtt.Message) {
} }
node, err := logic.GetNodeByID(id) node, err := logic.GetNodeByID(id)
if err != nil { 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) record, err := database.FetchRecord(database.NODES_TABLE_NAME, id)
if err != nil { if err != nil {
logger.Log(0, "error reading database ", err.Error()) logger.Log(3, "error reading database ", err.Error())
return return
} }
logger.Log(0, "record from database") logger.Log(3, "record from database")
logger.Log(0, record) logger.Log(3, record)
return return
} }
decrypted, decryptErr := decryptMsg(&node, msg.Payload()) 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()) logger.Log(1, "error unmarshaling payload ", err.Error())
return 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 var sendPeerUpdate bool
switch hostUpdate.Action { switch hostUpdate.Action {
case models.UpdateHost: case models.UpdateHost:
sendPeerUpdate = updateHostFromClient(&hostUpdate.Host, currentHost) sendPeerUpdate = logic.UpdateHostFromClient(&hostUpdate.Host, currentHost)
err := logic.UpsertHost(currentHost) err := logic.UpsertHost(currentHost)
if err != nil { if err != nil {
logger.Log(0, "failed to update host: ", currentHost.ID.String(), err.Error()) 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()) 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 servercfg.Is_EE && ifaceDelta {
// if err = logic.EnterpriseResetAllPeersFailovers(currentHost.ID.String(), currentHost.Network); err != nil { // 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) // 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) }(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 // UpdateMetrics message Handler -- handles updates from client nodes for metrics
func UpdateMetrics(client mqtt.Client, msg mqtt.Message) { func UpdateMetrics(client mqtt.Client, msg mqtt.Message) {
if servercfg.Is_EE { if servercfg.Is_EE {
@@ -370,7 +345,7 @@ func updateNodeMetrics(currentNode *models.Node, newMetrics *models.Metrics) boo
for _, node := range nodes { for _, node := range nodes {
if !newMetrics.Connectivity[node.ID.String()].Connected && if !newMetrics.Connectivity[node.ID.String()].Connected &&
len(newMetrics.Connectivity[node.ID.String()].NodeName) > 0 && len(newMetrics.Connectivity[node.ID.String()].NodeName) > 0 &&
node.Connected == true && node.Connected &&
len(node.FailoverNode) > 0 && len(node.FailoverNode) > 0 &&
!node.Failover { !node.Failover {
newMetrics.FailoverPeers[node.ID.String()] = node.FailoverNode.String() newMetrics.FailoverPeers[node.ID.String()] = node.FailoverNode.String()

View File

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

View File

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

Binary file not shown.

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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 Jason@zx2c4.com"
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
}

View File

@@ -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
}

View File

@@ -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)
// }
// }

View File

@@ -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
}
}
}

View File

@@ -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
}
}

View File

@@ -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
}

View File

@@ -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
scripts/nm-upgrade.sh Normal file
View File

@@ -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 "-----------------------------------------------------------------"

View File

@@ -76,15 +76,7 @@ func GetServerConfig() config.ServerConfig {
cfg.ClientID = authInfo[1] cfg.ClientID = authInfo[1]
cfg.ClientSecret = authInfo[2] cfg.ClientSecret = authInfo[2]
cfg.FrontendURL = GetFrontendURL() cfg.FrontendURL = GetFrontendURL()
if GetRce() {
cfg.RCE = "on"
} else {
cfg.RCE = "off"
}
cfg.Telemetry = Telemetry() cfg.Telemetry = Telemetry()
cfg.ManageIPTables = ManageIPTables()
services := strings.Join(GetPortForwardServiceList(), ",")
cfg.PortForwardServices = services
cfg.Server = GetServer() cfg.Server = GetServer()
cfg.Verbosity = GetVerbosity() cfg.Verbosity = GetVerbosity()
cfg.IsEE = "no" cfg.IsEE = "no"
@@ -379,18 +371,6 @@ func Telemetry() string {
return telemetry 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 // GetServer - gets the server name
func GetServer() string { func GetServer() string {
server := "" server := ""
@@ -528,19 +508,6 @@ func GetPlatform() string {
return platform 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 // GetSQLConn - get the sql connection string
func GetSQLConn() string { func GetSQLConn() string {
sqlconn := "http://" sqlconn := "http://"
@@ -552,17 +519,6 @@ func GetSQLConn() string {
return sqlconn 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 // GetNodeID - gets the node id
func GetNodeID() string { func GetNodeID() string {
var id string var id string
@@ -640,11 +596,6 @@ func GetAzureTenant() string {
return azureTenant 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 // GetMQServerPort - get mq port for server
func GetMQServerPort() string { func GetMQServerPort() string {
port := "1883" //default port := "1883" //default

View File

@@ -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
}

View File

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

View File

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

View File

@@ -467,17 +467,14 @@ func TestUpdateNetwork(t *testing.T) {
}) })
t.Run("UpdatePostUP", func(t *testing.T) { t.Run("UpdatePostUP", func(t *testing.T) {
type Network struct { type Network struct {
DefaultPostUp string
} }
var network Network 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") response, err := api(t, network, http.MethodPut, baseURL+"/api/networks/skynet", "secretkey")
assert.Nil(t, err, err) assert.Nil(t, err, err)
assert.Equal(t, http.StatusOK, response.StatusCode) assert.Equal(t, http.StatusOK, response.StatusCode)
defer response.Body.Close() defer response.Body.Close()
err = json.NewDecoder(response.Body).Decode(&returnedNetwork) err = json.NewDecoder(response.Body).Decode(&returnedNetwork)
assert.Nil(t, err, err) assert.Nil(t, err, err)
assert.Equal(t, network.DefaultPostUp, returnedNetwork.DefaultPostUp)
}) })
t.Run("UpdatePostDown", func(t *testing.T) { t.Run("UpdatePostDown", func(t *testing.T) {
type Network struct { type Network struct {