mirror of
https://github.com/gravitl/netmaker.git
synced 2025-10-28 03:01:48 +08:00
merge conflicts resolved
This commit is contained in:
22
cli/cmd/host/create_relay.go
Normal file
22
cli/cmd/host/create_relay.go
Normal 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)
|
||||
}
|
||||
20
cli/cmd/host/delete_relay.go
Normal file
20
cli/cmd/host/delete_relay.go
Normal 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)
|
||||
}
|
||||
@@ -38,6 +38,7 @@ var hostUpdateCmd = &cobra.Command{
|
||||
log.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
apiHost.ID = args[0]
|
||||
apiHost.EndpointIP = endpoint
|
||||
apiHost.Name = name
|
||||
apiHost.ListenPort = listenPort
|
||||
|
||||
@@ -41,19 +41,13 @@ var networkCreateCmd = &cobra.Command{
|
||||
if defaultACL {
|
||||
network.DefaultACL = "yes"
|
||||
}
|
||||
if pointToSite {
|
||||
network.IsPointToSite = "yes"
|
||||
}
|
||||
network.DefaultInterface = defaultInterface
|
||||
network.DefaultListenPort = int32(defaultListenPort)
|
||||
network.NodeLimit = int32(nodeLimit)
|
||||
network.DefaultPostUp = defaultPostUp
|
||||
network.DefaultPostDown = defaultPostDown
|
||||
network.DefaultKeepalive = int32(defaultKeepalive)
|
||||
if allowManualSignUp {
|
||||
network.AllowManualSignUp = "yes"
|
||||
}
|
||||
network.LocalRange = localRange
|
||||
network.DefaultExtClientDNS = defaultExtClientDNS
|
||||
network.DefaultMTU = int32(defaultMTU)
|
||||
}
|
||||
@@ -70,11 +64,7 @@ func init() {
|
||||
networkCreateCmd.Flags().BoolVar(&udpHolePunch, "udp_hole_punch", false, "Enable UDP Hole Punching ?")
|
||||
networkCreateCmd.Flags().BoolVar(&localNetwork, "local", false, "Is the network local (LAN) ?")
|
||||
networkCreateCmd.Flags().BoolVar(&defaultACL, "default_acl", false, "Enable default Access Control List ?")
|
||||
networkCreateCmd.Flags().BoolVar(&pointToSite, "point_to_site", false, "Enforce all clients to have only 1 central peer ?")
|
||||
networkCreateCmd.Flags().StringVar(&defaultInterface, "interface", "", "Name of the network interface")
|
||||
networkCreateCmd.Flags().StringVar(&defaultPostUp, "post_up", "", "Commands to run after server is up `;` separated")
|
||||
networkCreateCmd.Flags().StringVar(&defaultPostDown, "post_down", "", "Commands to run after server is down `;` separated")
|
||||
networkCreateCmd.Flags().StringVar(&localRange, "local_range", "", "Local CIDR range")
|
||||
networkCreateCmd.Flags().StringVar(&defaultExtClientDNS, "ext_client_dns", "", "IPv4 address of DNS server to be used by external clients")
|
||||
networkCreateCmd.Flags().IntVar(&defaultListenPort, "listen_port", 51821, "Default wireguard port each node will attempt to use")
|
||||
networkCreateCmd.Flags().IntVar(&nodeLimit, "node_limit", 999999999, "Maximum number of nodes that can be associated with this network")
|
||||
|
||||
@@ -8,15 +8,11 @@ var (
|
||||
udpHolePunch bool
|
||||
localNetwork bool
|
||||
defaultACL bool
|
||||
pointToSite bool
|
||||
defaultInterface string
|
||||
defaultListenPort int
|
||||
nodeLimit int
|
||||
defaultPostUp string
|
||||
defaultPostDown string
|
||||
defaultKeepalive int
|
||||
allowManualSignUp bool
|
||||
localRange string
|
||||
defaultExtClientDNS string
|
||||
defaultMTU int
|
||||
)
|
||||
|
||||
@@ -44,19 +44,13 @@ var networkUpdateCmd = &cobra.Command{
|
||||
if defaultACL {
|
||||
network.DefaultACL = "yes"
|
||||
}
|
||||
if pointToSite {
|
||||
network.IsPointToSite = "yes"
|
||||
}
|
||||
network.DefaultInterface = defaultInterface
|
||||
network.DefaultListenPort = int32(defaultListenPort)
|
||||
network.NodeLimit = int32(nodeLimit)
|
||||
network.DefaultPostUp = defaultPostUp
|
||||
network.DefaultPostDown = defaultPostDown
|
||||
network.DefaultKeepalive = int32(defaultKeepalive)
|
||||
if allowManualSignUp {
|
||||
network.AllowManualSignUp = "yes"
|
||||
}
|
||||
network.LocalRange = localRange
|
||||
network.DefaultExtClientDNS = defaultExtClientDNS
|
||||
network.DefaultMTU = int32(defaultMTU)
|
||||
}
|
||||
@@ -71,11 +65,7 @@ func init() {
|
||||
networkUpdateCmd.Flags().BoolVar(&udpHolePunch, "udp_hole_punch", false, "Enable UDP Hole Punching ?")
|
||||
networkUpdateCmd.Flags().BoolVar(&localNetwork, "local", false, "Is the network local (LAN) ?")
|
||||
networkUpdateCmd.Flags().BoolVar(&defaultACL, "default_acl", false, "Enable default Access Control List ?")
|
||||
networkUpdateCmd.Flags().BoolVar(&pointToSite, "point_to_site", false, "Enforce all clients to have only 1 central peer ?")
|
||||
networkUpdateCmd.Flags().StringVar(&defaultInterface, "interface", "", "Name of the network interface")
|
||||
networkUpdateCmd.Flags().StringVar(&defaultPostUp, "post_up", "", "Commands to run after server is up `;` separated")
|
||||
networkUpdateCmd.Flags().StringVar(&defaultPostDown, "post_down", "", "Commands to run after server is down `;` separated")
|
||||
networkUpdateCmd.Flags().StringVar(&localRange, "local_range", "", "Local CIDR range")
|
||||
networkUpdateCmd.Flags().StringVar(&defaultExtClientDNS, "ext_client_dns", "", "IPv4 address of DNS server to be used by external clients")
|
||||
networkUpdateCmd.Flags().IntVar(&defaultListenPort, "listen_port", 0, "Default wireguard port each node will attempt to use")
|
||||
networkUpdateCmd.Flags().IntVar(&nodeLimit, "node_limit", 0, "Maximum number of nodes that can be associated with this network")
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -34,8 +34,6 @@ var nodeUpdateCmd = &cobra.Command{
|
||||
node.Address = address
|
||||
node.Address6 = address6
|
||||
node.LocalAddress = localAddress
|
||||
node.PostUp = postUp
|
||||
node.PostDown = postDown
|
||||
node.PersistentKeepalive = int32(keepAlive)
|
||||
if relayAddrs != "" {
|
||||
node.RelayAddrs = strings.Split(relayAddrs, ",")
|
||||
@@ -50,6 +48,7 @@ var nodeUpdateCmd = &cobra.Command{
|
||||
node.DNSOn = dnsOn
|
||||
node.Connected = !disconnect
|
||||
}
|
||||
node.HostID = functions.GetNodeByID(networkName, nodeID).Host.ID.String()
|
||||
functions.PrettyPrint(functions.UpdateNode(networkName, nodeID, node))
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package functions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gravitl/netmaker/models"
|
||||
@@ -31,3 +32,16 @@ func UpdateHostNetworks(hostID string, networks []string) *hostNetworksUpdatePay
|
||||
Networks: networks,
|
||||
})
|
||||
}
|
||||
|
||||
// CreateRelay - turn a host into a relay
|
||||
func CreateRelay(hostID string, relayedHosts []string) *models.ApiHost {
|
||||
return request[models.ApiHost](http.MethodPost, fmt.Sprintf("/api/hosts/%s/relay", hostID), &models.HostRelayRequest{
|
||||
HostID: hostID,
|
||||
RelayedHosts: relayedHosts,
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteRelay - remove relay role from a host
|
||||
func DeleteRelay(hostID string) *models.ApiHost {
|
||||
return request[models.ApiHost](http.MethodDelete, fmt.Sprintf("/api/hosts/%s/relay", hostID), nil)
|
||||
}
|
||||
|
||||
@@ -31,20 +31,6 @@ func DeleteNode(networkName, nodeID string) *models.SuccessResponse {
|
||||
return request[models.SuccessResponse](http.MethodDelete, fmt.Sprintf("/api/nodes/%s/%s", networkName, nodeID), nil)
|
||||
}
|
||||
|
||||
// CreateRelay - turn a node into a relay
|
||||
func CreateRelay(networkName, nodeID string, relayAddresses []string) *models.ApiNode {
|
||||
return request[models.ApiNode](http.MethodPost, fmt.Sprintf("/api/nodes/%s/%s/createrelay", networkName, nodeID), &models.RelayRequest{
|
||||
NetID: networkName,
|
||||
NodeID: nodeID,
|
||||
RelayAddrs: relayAddresses,
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteRelay - remove relay role from a node
|
||||
func DeleteRelay(networkName, nodeID string) *models.ApiNode {
|
||||
return request[models.ApiNode](http.MethodDelete, fmt.Sprintf("/api/nodes/%s/%s/deleterelay", networkName, nodeID), nil)
|
||||
}
|
||||
|
||||
// CreateEgress - turn a node into an egress
|
||||
func CreateEgress(networkName, nodeID string, payload *models.EgressGatewayRequest) *models.ApiNode {
|
||||
return request[models.ApiNode](http.MethodPost, fmt.Sprintf("/api/nodes/%s/%s/creategateway", networkName, nodeID), payload)
|
||||
|
||||
@@ -4,15 +4,6 @@ services:
|
||||
netmaker:
|
||||
container_name: netmaker
|
||||
image: gravitl/netmaker:v0.17.1-ee
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
- NET_RAW
|
||||
- SYS_MODULE
|
||||
sysctls:
|
||||
- net.ipv4.ip_forward=1
|
||||
- net.ipv4.conf.all.src_valid_mark=1
|
||||
- net.ipv6.conf.all.disable_ipv6=0
|
||||
- net.ipv6.conf.all.forwarding=1
|
||||
restart: always
|
||||
volumes:
|
||||
- dnsconfig:/root/config/dnsconfig
|
||||
@@ -35,10 +26,7 @@ services:
|
||||
MQ_HOST: "mq"
|
||||
MQ_PORT: "443"
|
||||
MQ_SERVER_PORT: "1883"
|
||||
HOST_NETWORK: "off"
|
||||
VERBOSITY: "1"
|
||||
MANAGE_IPTABLES: "on"
|
||||
PORT_FORWARD_SERVICES: "dns"
|
||||
METRICS_EXPORTER: "on"
|
||||
LICENSE_KEY: "YOUR_LICENSE_KEY"
|
||||
NETMAKER_ACCOUNT_ID: "YOUR_ACCOUNT_ID"
|
||||
|
||||
@@ -4,15 +4,6 @@ services:
|
||||
netmaker: # The Primary Server for running Netmaker
|
||||
container_name: netmaker
|
||||
image: gravitl/netmaker:v0.17.1
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
- NET_RAW
|
||||
- SYS_MODULE
|
||||
sysctls:
|
||||
- net.ipv4.ip_forward=1
|
||||
- net.ipv4.conf.all.src_valid_mark=1
|
||||
- net.ipv6.conf.all.disable_ipv6=0
|
||||
- net.ipv6.conf.all.forwarding=1
|
||||
restart: always
|
||||
volumes: # Volume mounts necessary for sql, coredns, and mqtt
|
||||
- dnsconfig:/root/config/dnsconfig
|
||||
@@ -26,11 +17,9 @@ services:
|
||||
COREDNS_ADDR: "SERVER_PUBLIC_IP" # Address of the CoreDNS server. Defaults to SERVER_HOST
|
||||
DNS_MODE: "on" # Enables DNS Mode, meaning all nodes will set hosts file for private dns settings.
|
||||
API_PORT: "8081" # The HTTP API port for Netmaker. Used for API calls / communication from front end. If changed, need to change port of BACKEND_URL for netmaker-ui.
|
||||
CLIENT_MODE: "on" # Depricated. CLIENT_MODE should always be ON
|
||||
REST_BACKEND: "on" # Enables the REST backend (API running on API_PORT at SERVER_HTTP_HOST). Change to "off" to turn off.
|
||||
DISABLE_REMOTE_IP_CHECK: "off" # If turned "on", Server will not set Host based on remote IP check. This is already overridden if SERVER_HOST is set. Turned "off" by default.
|
||||
TELEMETRY: "on" # Whether or not to send telemetry data to help improve Netmaker. Switch to "off" to opt out of sending telemetry.
|
||||
RCE: "off" # Enables setting PostUp and PostDown (arbitrary commands) on nodes from the server. Off by default.
|
||||
MASTER_KEY: "REPLACE_MASTER_KEY" # The admin master key for accessing the API. Change this in any production installation.
|
||||
CORS_ALLOWED_ORIGIN: "*" # The "allowed origin" for API requests. Change to restrict where API requests can come from with comma-separated URLs. ex:- https://dashboard.netmaker.domain1.com,https://dashboard.netmaker.domain2.com
|
||||
DISPLAY_KEYS: "on" # Show keys permanently in UI (until deleted) as opposed to 1-time display.
|
||||
@@ -39,10 +28,7 @@ services:
|
||||
MQ_HOST: "mq" # the address of the mq server. If running from docker compose it will be "mq". Otherwise, need to input address. If using "host networking", it will find and detect the IP of the mq container.
|
||||
MQ_SERVER_PORT: "1883" # the reachable port of MQ by the server - change if internal MQ port changes (or use external port if MQ is not on the same machine)
|
||||
MQ_PORT: "443" # the reachable port of MQ - change if external MQ port changes (port on proxy, not necessarily the one exposed in docker-compose)
|
||||
HOST_NETWORK: "off" # whether or not host networking is turned on. Only turn on if configured for host networking (see docker-compose.hostnetwork.yml). Will set host-level settings like iptables.
|
||||
VERBOSITY: "1" # logging verbosity level - 1, 2, or 3
|
||||
MANAGE_IPTABLES: "on" # deprecated
|
||||
PORT_FORWARD_SERVICES: "dns" # decide which services to port forward ("dns","ssh", or "mq")
|
||||
# this section is for OAuth
|
||||
AUTH_PROVIDER: "" # "<azure-ad|github|google|oidc>"
|
||||
CLIENT_ID: "" # "<client id of your oauth provider>"
|
||||
|
||||
@@ -4,15 +4,6 @@ services:
|
||||
netmaker:
|
||||
container_name: netmaker
|
||||
image: gravitl/netmaker:v0.17.1
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
- NET_RAW
|
||||
- SYS_MODULE
|
||||
sysctls:
|
||||
- net.ipv4.ip_forward=1
|
||||
- net.ipv4.conf.all.src_valid_mark=1
|
||||
- net.ipv6.conf.all.disable_ipv6=0
|
||||
- net.ipv6.conf.all.forwarding=1
|
||||
restart: always
|
||||
volumes:
|
||||
- dnsconfig:/root/config/dnsconfig
|
||||
@@ -27,7 +18,6 @@ services:
|
||||
DNS_MODE: "on"
|
||||
SERVER_HTTP_HOST: "api.NETMAKER_BASE_DOMAIN"
|
||||
API_PORT: "8081"
|
||||
CLIENT_MODE: "on"
|
||||
MASTER_KEY: "REPLACE_MASTER_KEY"
|
||||
CORS_ALLOWED_ORIGIN: "*"
|
||||
DISPLAY_KEYS: "on"
|
||||
@@ -36,7 +26,6 @@ services:
|
||||
MQ_HOST: "mq"
|
||||
MQ_PORT: "443"
|
||||
MQ_SERVER_PORT: "1883"
|
||||
HOST_NETWORK: "off"
|
||||
VERBOSITY: "1"
|
||||
MANAGE_IPTABLES: "on"
|
||||
PORT_FORWARD_SERVICES: "dns"
|
||||
|
||||
@@ -61,10 +61,7 @@ type ServerConfig struct {
|
||||
FrontendURL string `yaml:"frontendurl"`
|
||||
DisplayKeys string `yaml:"displaykeys"`
|
||||
AzureTenant string `yaml:"azuretenant"`
|
||||
RCE string `yaml:"rce"`
|
||||
Telemetry string `yaml:"telemetry"`
|
||||
ManageIPTables string `yaml:"manageiptables"`
|
||||
PortForwardServices string `yaml:"portforwardservices"`
|
||||
HostNetwork string `yaml:"hostnetwork"`
|
||||
MQPort string `yaml:"mqport"`
|
||||
MQServerPort string `yaml:"mqserverport"`
|
||||
|
||||
@@ -160,7 +160,7 @@ func createDNS(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
entry, err = CreateDNS(entry)
|
||||
entry, err = logic.CreateDNS(entry)
|
||||
if err != nil {
|
||||
logger.Log(0, r.Header.Get("user"),
|
||||
fmt.Sprintf("Failed to create DNS entry %+v: %v", entry, err))
|
||||
@@ -223,22 +223,6 @@ func deleteDNS(w http.ResponseWriter, r *http.Request) {
|
||||
json.NewEncoder(w).Encode(entrytext + " deleted.")
|
||||
}
|
||||
|
||||
// CreateDNS - creates a DNS entry
|
||||
func CreateDNS(entry models.DNSEntry) (models.DNSEntry, error) {
|
||||
|
||||
data, err := json.Marshal(&entry)
|
||||
if err != nil {
|
||||
return models.DNSEntry{}, err
|
||||
}
|
||||
key, err := logic.GetRecordKey(entry.Name, entry.Network)
|
||||
if err != nil {
|
||||
return models.DNSEntry{}, err
|
||||
}
|
||||
err = database.Insert(key, string(data), database.DNS_TABLE_NAME)
|
||||
|
||||
return entry, err
|
||||
}
|
||||
|
||||
// GetDNSEntry - gets a DNS entry
|
||||
func GetDNSEntry(domain string, network string) (models.DNSEntry, error) {
|
||||
var entry models.DNSEntry
|
||||
|
||||
@@ -1,35 +1,45 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
|
||||
var dnsHost models.Host
|
||||
|
||||
func TestGetAllDNS(t *testing.T) {
|
||||
database.InitializeDatabase()
|
||||
deleteAllDNS(t)
|
||||
deleteAllNetworks()
|
||||
createNet()
|
||||
createHost()
|
||||
t.Run("NoEntries", func(t *testing.T) {
|
||||
entries, err := logic.GetAllDNS()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, []models.DNSEntry(nil), entries)
|
||||
})
|
||||
t.Run("OneEntry", func(t *testing.T) {
|
||||
entry := models.DNSEntry{"10.0.0.3", "", "newhost", "skynet"}
|
||||
CreateDNS(entry)
|
||||
entry := models.DNSEntry{
|
||||
"10.0.0.3", "", "newhost", "skynet",
|
||||
}
|
||||
_, err := logic.CreateDNS(entry)
|
||||
assert.Nil(t, err)
|
||||
entries, err := logic.GetAllDNS()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 1, len(entries))
|
||||
})
|
||||
t.Run("MultipleEntry", func(t *testing.T) {
|
||||
entry := models.DNSEntry{"10.0.0.7", "", "anotherhost", "skynet"}
|
||||
CreateDNS(entry)
|
||||
_, err := logic.CreateDNS(entry)
|
||||
assert.Nil(t, err)
|
||||
entries, err := logic.GetAllDNS()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(entries))
|
||||
@@ -41,22 +51,42 @@ func TestGetNodeDNS(t *testing.T) {
|
||||
deleteAllDNS(t)
|
||||
deleteAllNetworks()
|
||||
createNet()
|
||||
createHost()
|
||||
t.Run("NoNodes", func(t *testing.T) {
|
||||
dns, err := logic.GetNodeDNS("skynet")
|
||||
assert.EqualError(t, err, "could not find any records")
|
||||
assert.Equal(t, []models.DNSEntry(nil), dns)
|
||||
})
|
||||
t.Run("NodeExists", func(t *testing.T) {
|
||||
createnode := models.Node{PublicKey: "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Name: "testnode", Endpoint: "10.0.0.1", MacAddress: "01:02:03:04:05:06", Password: "password", Network: "skynet", OS: "linux", DNSOn: "yes"}
|
||||
err := logic.CreateNode(&createnode)
|
||||
createHost()
|
||||
_, ipnet, _ := net.ParseCIDR("10.0.0.1/32")
|
||||
tmpCNode := models.CommonNode{
|
||||
ID: uuid.New(),
|
||||
Network: "skynet",
|
||||
Address: *ipnet,
|
||||
DNSOn: true,
|
||||
}
|
||||
createnode := models.Node{
|
||||
CommonNode: tmpCNode,
|
||||
}
|
||||
err := logic.AssociateNodeToHost(&createnode, &dnsHost)
|
||||
assert.Nil(t, err)
|
||||
dns, err := logic.GetNodeDNS("skynet")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "10.0.0.1", dns[0].Address)
|
||||
})
|
||||
t.Run("MultipleNodes", func(t *testing.T) {
|
||||
createnode := &models.LegacyNode{PublicKey: "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Endpoint: "10.100.100.3", MacAddress: "01:02:03:04:05:07", Password: "password", Network: "skynet"}
|
||||
err := logic.CreateNode(createnode)
|
||||
_, ipnet, _ := net.ParseCIDR("10.100.100.3/32")
|
||||
tmpCNode := models.CommonNode{
|
||||
ID: uuid.New(),
|
||||
Network: "skynet",
|
||||
Address: *ipnet,
|
||||
DNSOn: true,
|
||||
}
|
||||
createnode := models.Node{
|
||||
CommonNode: tmpCNode,
|
||||
}
|
||||
err := logic.AssociateNodeToHost(&createnode, &dnsHost)
|
||||
assert.Nil(t, err)
|
||||
dns, err := logic.GetNodeDNS("skynet")
|
||||
assert.Nil(t, err)
|
||||
@@ -85,15 +115,17 @@ func TestGetCustomDNS(t *testing.T) {
|
||||
assert.Equal(t, 0, len(dns))
|
||||
})
|
||||
t.Run("EntryExist", func(t *testing.T) {
|
||||
entry := models.DNSEntry{"10.0.0.3", "", "newhost", "skynet"}
|
||||
CreateDNS(entry)
|
||||
entry := models.DNSEntry{"10.0.0.3", "", "custom1", "skynet"}
|
||||
_, err := logic.CreateDNS(entry)
|
||||
assert.Nil(t, err)
|
||||
dns, err := logic.GetCustomDNS("skynet")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 1, len(dns))
|
||||
})
|
||||
t.Run("MultipleEntries", func(t *testing.T) {
|
||||
entry := models.DNSEntry{"10.0.0.4", "", "host4", "skynet"}
|
||||
CreateDNS(entry)
|
||||
_, err := logic.CreateDNS(entry)
|
||||
assert.Nil(t, err)
|
||||
dns, err := logic.GetCustomDNS("skynet")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(dns))
|
||||
@@ -112,7 +144,7 @@ func TestGetDNSEntryNum(t *testing.T) {
|
||||
})
|
||||
t.Run("NodeExists", func(t *testing.T) {
|
||||
entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"}
|
||||
_, err := CreateDNS(entry)
|
||||
_, err := logic.CreateDNS(entry)
|
||||
assert.Nil(t, err)
|
||||
num, err := logic.GetDNSEntryNum("newhost", "skynet")
|
||||
assert.Nil(t, err)
|
||||
@@ -131,7 +163,7 @@ func TestGetDNS(t *testing.T) {
|
||||
})
|
||||
t.Run("CustomDNSExists", func(t *testing.T) {
|
||||
entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"}
|
||||
_, err := CreateDNS(entry)
|
||||
_, err := logic.CreateDNS(entry)
|
||||
assert.Nil(t, err)
|
||||
dns, err := logic.GetDNS("skynet")
|
||||
t.Log(dns)
|
||||
@@ -151,7 +183,7 @@ func TestGetDNS(t *testing.T) {
|
||||
})
|
||||
t.Run("NodeAndCustomDNS", func(t *testing.T) {
|
||||
entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"}
|
||||
_, err := CreateDNS(entry)
|
||||
_, err := logic.CreateDNS(entry)
|
||||
assert.Nil(t, err)
|
||||
dns, err := logic.GetDNS("skynet")
|
||||
t.Log(dns)
|
||||
@@ -169,7 +201,7 @@ func TestCreateDNS(t *testing.T) {
|
||||
deleteAllNetworks()
|
||||
createNet()
|
||||
entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"}
|
||||
dns, err := CreateDNS(entry)
|
||||
dns, err := logic.CreateDNS(entry)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "newhost", dns.Name)
|
||||
}
|
||||
@@ -204,12 +236,13 @@ func TestSetDNS(t *testing.T) {
|
||||
assert.False(t, info.IsDir())
|
||||
content, err := os.ReadFile("./config/dnsconfig/netmaker.hosts")
|
||||
assert.Nil(t, err)
|
||||
assert.Contains(t, string(content), "testnode.skynet")
|
||||
assert.Contains(t, string(content), "linuxhost.skynet")
|
||||
})
|
||||
t.Run("EntryExists", func(t *testing.T) {
|
||||
entry := models.DNSEntry{"10.0.0.3", "", "newhost", "skynet"}
|
||||
CreateDNS(entry)
|
||||
err := logic.SetDNS()
|
||||
_, err := logic.CreateDNS(entry)
|
||||
assert.Nil(t, err)
|
||||
err = logic.SetDNS()
|
||||
assert.Nil(t, err)
|
||||
info, err := os.Stat("./config/dnsconfig/netmaker.hosts")
|
||||
assert.Nil(t, err)
|
||||
@@ -228,7 +261,7 @@ func TestGetDNSEntry(t *testing.T) {
|
||||
createNet()
|
||||
createTestNode()
|
||||
entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"}
|
||||
CreateDNS(entry)
|
||||
_, _ = logic.CreateDNS(entry)
|
||||
t.Run("wrong net", func(t *testing.T) {
|
||||
entry, err := GetDNSEntry("newhost", "w286 Toronto Street South, Uxbridge, ONirecat")
|
||||
assert.EqualError(t, err, "no result found")
|
||||
@@ -251,40 +284,13 @@ func TestGetDNSEntry(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// func TestUpdateDNS(t *testing.T) {
|
||||
// var newentry models.DNSEntry
|
||||
// database.InitializeDatabase()
|
||||
// deleteAllDNS(t)
|
||||
// deleteAllNetworks()
|
||||
// createNet()
|
||||
// entry := models.DNSEntry{"10.0.0.2", "newhost", "skynet"}
|
||||
// CreateDNS(entry)
|
||||
// t.Run("change address", func(t *testing.T) {
|
||||
// newentry.Address = "10.0.0.75"
|
||||
// updated, err := UpdateDNS(newentry, entry)
|
||||
// assert.Nil(t, err)
|
||||
// assert.Equal(t, newentry.Address, updated.Address)
|
||||
// })
|
||||
// t.Run("change name", func(t *testing.T) {
|
||||
// newentry.Name = "newname"
|
||||
// updated, err := UpdateDNS(newentry, entry)
|
||||
// assert.Nil(t, err)
|
||||
// assert.Equal(t, newentry.Name, updated.Name)
|
||||
// })
|
||||
// t.Run("change network", func(t *testing.T) {
|
||||
// newentry.Network = "wirecat"
|
||||
// updated, err := UpdateDNS(newentry, entry)
|
||||
// assert.Nil(t, err)
|
||||
// assert.NotEqual(t, newentry.Network, updated.Network)
|
||||
// })
|
||||
// }
|
||||
func TestDeleteDNS(t *testing.T) {
|
||||
database.InitializeDatabase()
|
||||
deleteAllDNS(t)
|
||||
deleteAllNetworks()
|
||||
createNet()
|
||||
entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"}
|
||||
CreateDNS(entry)
|
||||
_, _ = logic.CreateDNS(entry)
|
||||
t.Run("EntryExists", func(t *testing.T) {
|
||||
err := logic.DeleteDNS("newhost", "skynet")
|
||||
assert.Nil(t, err)
|
||||
@@ -351,8 +357,8 @@ func TestValidateDNSUpdate(t *testing.T) {
|
||||
})
|
||||
t.Run("NameUnique", func(t *testing.T) {
|
||||
change := models.DNSEntry{"10.0.0.2", "", "myhost", "wirecat"}
|
||||
CreateDNS(entry)
|
||||
CreateDNS(change)
|
||||
_, _ = logic.CreateDNS(entry)
|
||||
_, _ = logic.CreateDNS(change)
|
||||
err := logic.ValidateDNSUpdate(change, entry)
|
||||
assert.NotNil(t, err)
|
||||
assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'name_unique' tag")
|
||||
@@ -401,13 +407,25 @@ func TestValidateDNSCreate(t *testing.T) {
|
||||
})
|
||||
t.Run("NameUnique", func(t *testing.T) {
|
||||
entry := models.DNSEntry{"10.0.0.2", "", "myhost", "skynet"}
|
||||
_, _ = CreateDNS(entry)
|
||||
_, _ = logic.CreateDNS(entry)
|
||||
err := logic.ValidateDNSCreate(entry)
|
||||
assert.NotNil(t, err)
|
||||
assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'name_unique' tag")
|
||||
})
|
||||
}
|
||||
|
||||
func createHost() {
|
||||
k, _ := wgtypes.ParseKey("DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=")
|
||||
dnsHost = models.Host{
|
||||
ID: uuid.New(),
|
||||
PublicKey: k.PublicKey(),
|
||||
HostPass: "password",
|
||||
OS: "linux",
|
||||
Name: "dnshost",
|
||||
}
|
||||
_ = logic.CreateHost(&dnsHost)
|
||||
}
|
||||
|
||||
func deleteAllDNS(t *testing.T) {
|
||||
dns, err := logic.GetAllDNS()
|
||||
assert.Nil(t, err)
|
||||
|
||||
@@ -12,12 +12,9 @@ import (
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/mq"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
type hostNetworksUpdatePayload struct {
|
||||
Networks []string `json:"networks"`
|
||||
}
|
||||
|
||||
func hostHandlers(r *mux.Router) {
|
||||
r.HandleFunc("/api/hosts", logic.SecurityCheck(true, http.HandlerFunc(getHosts))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/hosts/{hostid}", logic.SecurityCheck(true, http.HandlerFunc(updateHost))).Methods(http.MethodPut)
|
||||
@@ -26,6 +23,7 @@ func hostHandlers(r *mux.Router) {
|
||||
r.HandleFunc("/api/hosts/{hostid}/networks/{network}", logic.SecurityCheck(true, http.HandlerFunc(deleteHostFromNetwork))).Methods(http.MethodDelete)
|
||||
r.HandleFunc("/api/hosts/{hostid}/relay", logic.SecurityCheck(false, http.HandlerFunc(createHostRelay))).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/hosts/{hostid}/relay", logic.SecurityCheck(false, http.HandlerFunc(deleteHostRelay))).Methods(http.MethodDelete)
|
||||
r.HandleFunc("/api/hosts/adm/authenticate", authenticateHost).Methods(http.MethodPost)
|
||||
}
|
||||
|
||||
// swagger:route GET /api/hosts hosts getHosts
|
||||
@@ -99,6 +97,10 @@ func updateHost(w http.ResponseWriter, r *http.Request) {
|
||||
if updateRelay {
|
||||
logic.UpdateHostRelay(currHost.ID.String(), currHost.RelayedHosts, newHost.RelayedHosts)
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
|
||||
>>>>>>> f4851937c1746475fdac99e9c562623128ba16b1
|
||||
// publish host update through MQ
|
||||
if err := mq.HostUpdate(&models.HostUpdate{
|
||||
Action: models.UpdateHost,
|
||||
@@ -139,7 +141,33 @@ func deleteHost(w http.ResponseWriter, r *http.Request) {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
|
||||
if currHost.IsRelay {
|
||||
if _, _, err := logic.DeleteHostRelay(hostid); err != nil {
|
||||
logger.Log(0, r.Header.Get("user"), "failed to dissociate host from relays:", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
}
|
||||
if currHost.IsRelayed {
|
||||
relayHost, err := logic.GetHost(currHost.RelayedBy)
|
||||
if err != nil {
|
||||
logger.Log(0, r.Header.Get("user"), "failed to fetch relay host:", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
newRelayedHosts := make([]string, 0)
|
||||
for _, relayedHostID := range relayHost.RelayedHosts {
|
||||
if relayedHostID != hostid {
|
||||
newRelayedHosts = append(newRelayedHosts, relayedHostID)
|
||||
}
|
||||
}
|
||||
relayHost.RelayedHosts = newRelayedHosts
|
||||
if err := logic.UpsertHost(relayHost); err != nil {
|
||||
logger.Log(0, r.Header.Get("user"), "failed to update host relays:", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
}
|
||||
if err = logic.RemoveHost(currHost); err != nil {
|
||||
logger.Log(0, r.Header.Get("user"), "failed to delete a host:", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
@@ -254,3 +282,96 @@ func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
|
||||
logger.Log(2, r.Header.Get("user"), fmt.Sprintf("removed host %s from network %s", currHost.Name, network))
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
// swagger:route POST /api/hosts/adm/authenticate hosts authenticateHost
|
||||
//
|
||||
// Host based authentication for making further API calls.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: successResponse
|
||||
func authenticateHost(response http.ResponseWriter, request *http.Request) {
|
||||
var authRequest models.AuthParams
|
||||
var errorResponse = models.ErrorResponse{
|
||||
Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
|
||||
}
|
||||
|
||||
decoder := json.NewDecoder(request.Body)
|
||||
decoderErr := decoder.Decode(&authRequest)
|
||||
defer request.Body.Close()
|
||||
|
||||
if decoderErr != nil {
|
||||
errorResponse.Code = http.StatusBadRequest
|
||||
errorResponse.Message = decoderErr.Error()
|
||||
logger.Log(0, request.Header.Get("user"), "error decoding request body: ",
|
||||
decoderErr.Error())
|
||||
logic.ReturnErrorResponse(response, request, errorResponse)
|
||||
return
|
||||
}
|
||||
errorResponse.Code = http.StatusBadRequest
|
||||
if authRequest.ID == "" {
|
||||
errorResponse.Message = "W1R3: ID can't be empty"
|
||||
logger.Log(0, request.Header.Get("user"), errorResponse.Message)
|
||||
logic.ReturnErrorResponse(response, request, errorResponse)
|
||||
return
|
||||
} else if authRequest.Password == "" {
|
||||
errorResponse.Message = "W1R3: Password can't be empty"
|
||||
logger.Log(0, request.Header.Get("user"), errorResponse.Message)
|
||||
logic.ReturnErrorResponse(response, request, errorResponse)
|
||||
return
|
||||
}
|
||||
host, err := logic.GetHost(authRequest.ID)
|
||||
if err != nil {
|
||||
errorResponse.Code = http.StatusBadRequest
|
||||
errorResponse.Message = err.Error()
|
||||
logger.Log(0, request.Header.Get("user"),
|
||||
"error retrieving host: ", err.Error())
|
||||
logic.ReturnErrorResponse(response, request, errorResponse)
|
||||
return
|
||||
}
|
||||
err = bcrypt.CompareHashAndPassword([]byte(host.HostPass), []byte(authRequest.Password))
|
||||
if err != nil {
|
||||
errorResponse.Code = http.StatusUnauthorized
|
||||
errorResponse.Message = "unauthorized"
|
||||
logger.Log(0, request.Header.Get("user"),
|
||||
"error validating user password: ", err.Error())
|
||||
logic.ReturnErrorResponse(response, request, errorResponse)
|
||||
return
|
||||
}
|
||||
|
||||
tokenString, err := logic.CreateJWT(authRequest.ID, authRequest.MacAddress, "")
|
||||
if tokenString == "" {
|
||||
errorResponse.Code = http.StatusUnauthorized
|
||||
errorResponse.Message = "unauthorized"
|
||||
logger.Log(0, request.Header.Get("user"),
|
||||
fmt.Sprintf("%s: %v", errorResponse.Message, err))
|
||||
logic.ReturnErrorResponse(response, request, errorResponse)
|
||||
return
|
||||
}
|
||||
|
||||
var successResponse = models.SuccessResponse{
|
||||
Code: http.StatusOK,
|
||||
Message: "W1R3: Host " + authRequest.ID + " Authorized",
|
||||
Response: models.SuccessfulLoginResponse{
|
||||
AuthToken: tokenString,
|
||||
ID: authRequest.ID,
|
||||
},
|
||||
}
|
||||
successJSONResponse, jsonError := json.Marshal(successResponse)
|
||||
|
||||
if jsonError != nil {
|
||||
errorResponse.Code = http.StatusBadRequest
|
||||
errorResponse.Message = err.Error()
|
||||
logger.Log(0, request.Header.Get("user"),
|
||||
"error marshalling resp: ", err.Error())
|
||||
logic.ReturnErrorResponse(response, request, errorResponse)
|
||||
return
|
||||
}
|
||||
response.WriteHeader(http.StatusOK)
|
||||
response.Header().Set("Content-Type", "application/json")
|
||||
response.Write(successJSONResponse)
|
||||
}
|
||||
|
||||
78
controllers/migrate.go
Normal file
78
controllers/migrate.go
Normal 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)
|
||||
}
|
||||
@@ -185,13 +185,7 @@ func updateNetwork(w http.ResponseWriter, r *http.Request) {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
|
||||
if !servercfg.GetRce() {
|
||||
newNetwork.DefaultPostDown = network.DefaultPostDown
|
||||
newNetwork.DefaultPostUp = network.DefaultPostUp
|
||||
}
|
||||
|
||||
rangeupdate4, rangeupdate6, localrangeupdate, holepunchupdate, groupsDelta, userDelta, err := logic.UpdateNetwork(&network, &newNetwork)
|
||||
rangeupdate4, rangeupdate6, holepunchupdate, groupsDelta, userDelta, err := logic.UpdateNetwork(&network, &newNetwork)
|
||||
if err != nil {
|
||||
logger.Log(0, r.Header.Get("user"), "failed to update network: ",
|
||||
err.Error())
|
||||
@@ -237,17 +231,7 @@ func updateNetwork(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
}
|
||||
if localrangeupdate {
|
||||
err = logic.UpdateNetworkLocalAddresses(network.NetID)
|
||||
if err != nil {
|
||||
logger.Log(0, r.Header.Get("user"),
|
||||
fmt.Sprintf("failed to update network [%s] local addresses: %v",
|
||||
network.NetID, err.Error()))
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
}
|
||||
if rangeupdate4 || rangeupdate6 || localrangeupdate || holepunchupdate {
|
||||
if rangeupdate4 || rangeupdate6 || holepunchupdate {
|
||||
nodes, err := logic.GetNetworkNodes(network.NetID)
|
||||
if err != nil {
|
||||
logger.Log(0, r.Header.Get("user"),
|
||||
|
||||
@@ -4,10 +4,12 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
|
||||
type NetworkValidationTestCase struct {
|
||||
@@ -16,6 +18,8 @@ type NetworkValidationTestCase struct {
|
||||
errMessage string
|
||||
}
|
||||
|
||||
var netHost models.Host
|
||||
|
||||
func TestCreateNetwork(t *testing.T) {
|
||||
initialize()
|
||||
deleteAllNetworks()
|
||||
@@ -271,14 +275,6 @@ func TestValidateNetwork(t *testing.T) {
|
||||
},
|
||||
errMessage: "Field validation for 'DefaultKeepalive' failed on the 'max' tag",
|
||||
},
|
||||
{
|
||||
testname: "InvalidLocalRange",
|
||||
network: models.Network{
|
||||
NetID: "skynet",
|
||||
LocalRange: "192.168.0.1",
|
||||
},
|
||||
errMessage: "Field validation for 'LocalRange' failed on the 'cidr' tag",
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.testname, func(t *testing.T) {
|
||||
@@ -305,11 +301,12 @@ func TestIpv6Network(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, network.AddressRange6, "fde6:be04:fa5e:d076::/64")
|
||||
})
|
||||
node1 := models.LegacyNode{PublicKey: "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Name: "testnode", Endpoint: "10.0.0.50", MacAddress: "01:02:03:04:05:06", Password: "password", Network: "skynet6", OS: "linux"}
|
||||
nodeErr := logic.CreateNode(&node1)
|
||||
node1 := createNodeWithParams("skynet6", "")
|
||||
createNetHost()
|
||||
nodeErr := logic.AssociateNodeToHost(node1, &netHost)
|
||||
t.Run("Test node on network IPv6", func(t *testing.T) {
|
||||
assert.Nil(t, nodeErr)
|
||||
assert.Equal(t, "fde6:be04:fa5e:d076::1", node1.Address6)
|
||||
assert.Equal(t, "fde6:be04:fa5e:d076::1", node1.Address6.IP.String())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -358,3 +355,15 @@ func createNetDualStack() {
|
||||
logic.CreateNetwork(network)
|
||||
}
|
||||
}
|
||||
|
||||
func createNetHost() {
|
||||
k, _ := wgtypes.ParseKey("DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=")
|
||||
netHost = models.Host{
|
||||
ID: uuid.New(),
|
||||
PublicKey: k.PublicKey(),
|
||||
HostPass: "password",
|
||||
OS: "linux",
|
||||
Name: "nethost",
|
||||
}
|
||||
_ = logic.CreateHost(&netHost)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
@@ -26,7 +25,7 @@ func nodeHandlers(r *mux.Router) {
|
||||
r.HandleFunc("/api/nodes/{network}", authorize(false, true, "network", http.HandlerFunc(getNetworkNodes))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/nodes/{network}/{nodeid}", authorize(true, true, "node", http.HandlerFunc(getNode))).Methods(http.MethodGet)
|
||||
r.HandleFunc("/api/nodes/{network}/{nodeid}", authorize(false, true, "node", http.HandlerFunc(updateNode))).Methods(http.MethodPut)
|
||||
r.HandleFunc("/api/nodes/{network}/{nodeid}/migrate", authorize(true, true, "node", http.HandlerFunc(migrate))).Methods(http.MethodPut)
|
||||
r.HandleFunc("/api/nodes/{network}/{nodeid}/migrate", migrate).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/nodes/{network}/{nodeid}", authorize(true, true, "node", http.HandlerFunc(deleteNode))).Methods(http.MethodDelete)
|
||||
r.HandleFunc("/api/nodes/{network}/{nodeid}/createrelay", authorize(false, true, "user", http.HandlerFunc(createRelay))).Methods(http.MethodPost)
|
||||
r.HandleFunc("/api/nodes/{network}/{nodeid}/deleterelay", authorize(false, true, "user", http.HandlerFunc(deleteRelay))).Methods(http.MethodDelete)
|
||||
@@ -188,6 +187,7 @@ func nodeauth(next http.Handler) http.HandlerFunc {
|
||||
logic.ReturnErrorResponse(w, r, errorResponse)
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
@@ -524,7 +524,7 @@ func createNode(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if !logic.IsVersionComptatible(data.Host.Version) {
|
||||
err := errors.New("incomatible netclient version")
|
||||
err := errors.New("incompatible netclient version")
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
@@ -550,6 +550,7 @@ func createNode(w http.ResponseWriter, r *http.Request) {
|
||||
logic.ReturnErrorResponse(w, r, errorResponse)
|
||||
return
|
||||
}
|
||||
logic.DecrimentKey(networkName, data.Key)
|
||||
user, err := pro.GetNetworkUser(networkName, promodels.NetworkUserID(keyName))
|
||||
if err == nil {
|
||||
if user.ID != "" {
|
||||
@@ -577,6 +578,9 @@ func createNode(w http.ResponseWriter, r *http.Request) {
|
||||
server := servercfg.GetServerInfo()
|
||||
server.TrafficKey = key
|
||||
data.Node.Server = servercfg.GetServer()
|
||||
if !logic.HostExists(&data.Host) {
|
||||
logic.CheckHostPorts(&data.Host)
|
||||
}
|
||||
if err := logic.CreateHost(&data.Host); err != nil {
|
||||
if errors.Is(err, logic.ErrHostExists) {
|
||||
logger.Log(3, "host exists .. no need to create")
|
||||
@@ -586,8 +590,15 @@ func createNode(w http.ResponseWriter, r *http.Request) {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
logic.UpdateHost(&data.Host, host) // update the in memory struct values
|
||||
|
||||
logic.UpdateHostFromClient(&data.Host, host) // update the in memory struct values
|
||||
err = logic.UpsertHost(host)
|
||||
if err != nil {
|
||||
logger.Log(0, r.Header.Get("user"),
|
||||
fmt.Sprintf("failed to update host [ %s ]: %v", host.ID.String(), err))
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
data.Host = *host
|
||||
} else {
|
||||
logger.Log(0, "error creating host", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
@@ -628,6 +639,8 @@ func createNode(w http.ResponseWriter, r *http.Request) {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
data.Host.HostPass = "" // client should not change password after join
|
||||
// concealing hash
|
||||
response := models.NodeJoinResponse{
|
||||
Node: data.Node,
|
||||
ServerConfig: server,
|
||||
@@ -660,32 +673,33 @@ func createNode(w http.ResponseWriter, r *http.Request) {
|
||||
// Responses:
|
||||
// 200: nodeResponse
|
||||
func createEgressGateway(w http.ResponseWriter, r *http.Request) {
|
||||
var gateway models.EgressGatewayRequest
|
||||
var params = mux.Vars(r)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
err := json.NewDecoder(r.Body).Decode(&gateway)
|
||||
if err != nil {
|
||||
logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
gateway.NetID = params["network"]
|
||||
gateway.NodeID = params["nodeid"]
|
||||
node, err := logic.CreateEgressGateway(gateway)
|
||||
if err != nil {
|
||||
logger.Log(0, r.Header.Get("user"),
|
||||
fmt.Sprintf("failed to create egress gateway on node [%s] on network [%s]: %v",
|
||||
gateway.NodeID, gateway.NetID, err))
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
|
||||
apiNode := node.ConvertToAPINode()
|
||||
logger.Log(1, r.Header.Get("user"), "created egress gateway on node", gateway.NodeID, "on network", gateway.NetID)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(apiNode)
|
||||
|
||||
runUpdates(&node, true)
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("currently unimplemented"), "internal"))
|
||||
// var gateway models.EgressGatewayRequest
|
||||
// var params = mux.Vars(r)
|
||||
// w.Header().Set("Content-Type", "application/json")
|
||||
// err := json.NewDecoder(r.Body).Decode(&gateway)
|
||||
// if err != nil {
|
||||
// logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error())
|
||||
// logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
// return
|
||||
// }
|
||||
// gateway.NetID = params["network"]
|
||||
// gateway.NodeID = params["nodeid"]
|
||||
// node, err := logic.CreateEgressGateway(gateway)
|
||||
// if err != nil {
|
||||
// logger.Log(0, r.Header.Get("user"),
|
||||
// fmt.Sprintf("failed to create egress gateway on node [%s] on network [%s]: %v",
|
||||
// gateway.NodeID, gateway.NetID, err))
|
||||
// logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// apiNode := node.ConvertToAPINode()
|
||||
// logger.Log(1, r.Header.Get("user"), "created egress gateway on node", gateway.NodeID, "on network", gateway.NetID)
|
||||
// w.WriteHeader(http.StatusOK)
|
||||
// json.NewEncoder(w).Encode(apiNode)
|
||||
//
|
||||
// runUpdates(&node, true)
|
||||
}
|
||||
|
||||
// swagger:route DELETE /api/nodes/{network}/{nodeid}/deletegateway nodes deleteEgressGateway
|
||||
@@ -700,25 +714,26 @@ func createEgressGateway(w http.ResponseWriter, r *http.Request) {
|
||||
// Responses:
|
||||
// 200: nodeResponse
|
||||
func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
var params = mux.Vars(r)
|
||||
nodeid := params["nodeid"]
|
||||
netid := params["network"]
|
||||
node, err := logic.DeleteEgressGateway(netid, nodeid)
|
||||
if err != nil {
|
||||
logger.Log(0, r.Header.Get("user"),
|
||||
fmt.Sprintf("failed to delete egress gateway on node [%s] on network [%s]: %v",
|
||||
nodeid, netid, err))
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
return
|
||||
}
|
||||
|
||||
apiNode := node.ConvertToAPINode()
|
||||
logger.Log(1, r.Header.Get("user"), "deleted egress gateway on node", nodeid, "on network", netid)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(apiNode)
|
||||
|
||||
runUpdates(&node, true)
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("currently unimplemented"), "internal"))
|
||||
//w.Header().Set("Content-Type", "application/json")
|
||||
// var params = mux.Vars(r)
|
||||
// nodeid := params["nodeid"]
|
||||
// netid := params["network"]
|
||||
// node, err := logic.DeleteEgressGateway(netid, nodeid)
|
||||
// if err != nil {
|
||||
// logger.Log(0, r.Header.Get("user"),
|
||||
// fmt.Sprintf("failed to delete egress gateway on node [%s] on network [%s]: %v",
|
||||
// nodeid, netid, err))
|
||||
// logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// apiNode := node.ConvertToAPINode()
|
||||
// logger.Log(1, r.Header.Get("user"), "deleted egress gateway on node", nodeid, "on network", netid)
|
||||
// w.WriteHeader(http.StatusOK)
|
||||
// json.NewEncoder(w).Encode(apiNode)
|
||||
//
|
||||
// runUpdates(&node, true)
|
||||
}
|
||||
|
||||
// == INGRESS ==
|
||||
@@ -807,51 +822,6 @@ func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
|
||||
runUpdates(&node, true)
|
||||
}
|
||||
|
||||
// swagger:route PUT /api/nodes/{network}/{nodeid}/migrate nodes migrateNode
|
||||
//
|
||||
// Used to migrate a legacy node.
|
||||
//
|
||||
// Schemes: https
|
||||
//
|
||||
// Security:
|
||||
// oauth
|
||||
//
|
||||
// Responses:
|
||||
// 200: nodeJoinResponse
|
||||
func migrate(w http.ResponseWriter, r *http.Request) {
|
||||
// we decode our body request params
|
||||
data := models.JoinData{}
|
||||
err := json.NewDecoder(r.Body).Decode(&data)
|
||||
if err != nil {
|
||||
logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
params := mux.Vars(r)
|
||||
network, err := logic.GetNetwork(params["network"])
|
||||
if err != nil {
|
||||
logger.Log(0, "error retrieving network: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
key, err := logic.CreateAccessKey(models.AccessKey{}, network)
|
||||
if err != nil {
|
||||
logger.Log(0, "error creating key: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
data.Key = key.Value
|
||||
payload, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
logger.Log(0, "error encoding data: ", err.Error())
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
r.Body = io.NopCloser(strings.NewReader(string(payload)))
|
||||
r.ContentLength = int64(len(string(payload)))
|
||||
createNode(w, r)
|
||||
}
|
||||
|
||||
// swagger:route PUT /api/nodes/{network}/{nodeid} nodes updateNode
|
||||
//
|
||||
// Update an individual node.
|
||||
@@ -920,11 +890,6 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
|
||||
if currentNode.IsRelayed && (currentNode.Address.String() != newNode.Address.String() || currentNode.Address6.String() != newNode.Address6.String()) {
|
||||
relayedUpdate = true
|
||||
}
|
||||
|
||||
if !servercfg.GetRce() {
|
||||
newNode.PostDown = currentNode.PostDown
|
||||
newNode.PostUp = currentNode.PostUp
|
||||
}
|
||||
ifaceDelta := logic.IfaceDelta(¤tNode, newNode)
|
||||
|
||||
if ifaceDelta && servercfg.Is_EE {
|
||||
@@ -988,7 +953,6 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
|
||||
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
|
||||
return
|
||||
}
|
||||
|
||||
if r.Header.Get("ismaster") != "yes" {
|
||||
username := r.Header.Get("user")
|
||||
if username != "" && !doesUserOwnNode(username, params["network"], nodeid) {
|
||||
@@ -1002,9 +966,7 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
logic.ReturnSuccessResponse(w, r, nodeid+" deleted.")
|
||||
logger.Log(1, r.Header.Get("user"), "Deleted node", nodeid, "from network", params["network"])
|
||||
|
||||
if !fromNode {
|
||||
// notify node change
|
||||
if !fromNode { // notify node change
|
||||
runUpdates(&node, false)
|
||||
}
|
||||
go func() { // notify of peer change
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/logic/acls"
|
||||
"github.com/gravitl/netmaker/logic/acls/nodeacls"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
|
||||
var nonLinuxHost models.Host
|
||||
var linuxHost models.Host
|
||||
|
||||
func TestCreateEgressGateway(t *testing.T) {
|
||||
var gateway models.EgressGatewayRequest
|
||||
gateway.Interface = "eth0"
|
||||
@@ -21,45 +27,39 @@ func TestCreateEgressGateway(t *testing.T) {
|
||||
createNet()
|
||||
t.Run("NoNodes", func(t *testing.T) {
|
||||
node, err := logic.CreateEgressGateway(gateway)
|
||||
assert.Equal(t, models.LegacyNode{}, node)
|
||||
assert.Equal(t, models.Node{}, node)
|
||||
assert.EqualError(t, err, "could not find any records")
|
||||
})
|
||||
t.Run("Non-linux node", func(t *testing.T) {
|
||||
createnode := models.LegacyNode{PublicKey: "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Name: "testnode", Endpoint: "10.0.0.1", MacAddress: "01:02:03:04:05:06", Password: "password", Network: "skynet", OS: "windows"}
|
||||
err := logic.CreateNode(&createnode)
|
||||
createnode := createNodeWithParams("", "")
|
||||
createNodeHosts()
|
||||
createnode.HostID = nonLinuxHost.ID
|
||||
err := logic.AssociateNodeToHost(createnode, &nonLinuxHost)
|
||||
assert.Nil(t, err)
|
||||
gateway.NodeID = createnode.ID
|
||||
gateway.NodeID = createnode.ID.String()
|
||||
node, err := logic.CreateEgressGateway(gateway)
|
||||
assert.Equal(t, models.LegacyNode{}, node)
|
||||
assert.Equal(t, models.Node{}, node)
|
||||
assert.EqualError(t, err, "windows is unsupported for egress gateways")
|
||||
})
|
||||
t.Run("Success-Nat-Enabled", func(t *testing.T) {
|
||||
deleteAllNodes()
|
||||
testnode := createTestNode()
|
||||
gateway.NodeID = testnode.ID
|
||||
gateway.NodeID = testnode.ID.String()
|
||||
gateway.NatEnabled = "yes"
|
||||
|
||||
node, err := logic.CreateEgressGateway(gateway)
|
||||
t.Log(node.EgressGatewayNatEnabled)
|
||||
t.Log(node.PostUp)
|
||||
t.Log(node.PostDown)
|
||||
assert.Nil(t, err)
|
||||
assert.Contains(t, node.PostUp, "-j MASQUERADE")
|
||||
assert.Contains(t, node.PostDown, "-j MASQUERADE")
|
||||
})
|
||||
t.Run("Success-Nat-Disabled", func(t *testing.T) {
|
||||
deleteAllNodes()
|
||||
testnode := createTestNode()
|
||||
gateway.NodeID = testnode.ID
|
||||
gateway.NodeID = testnode.ID.String()
|
||||
gateway.NatEnabled = "no"
|
||||
|
||||
node, err := logic.CreateEgressGateway(gateway)
|
||||
t.Log(node.EgressGatewayNatEnabled)
|
||||
t.Log(node.PostUp)
|
||||
t.Log(node.PostDown)
|
||||
assert.Nil(t, err)
|
||||
assert.NotContains(t, node.PostUp, "-j MASUERADE")
|
||||
assert.NotContains(t, node.PostDown, "-j MASUERADE")
|
||||
})
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
var gateway models.EgressGatewayRequest
|
||||
@@ -68,14 +68,12 @@ func TestCreateEgressGateway(t *testing.T) {
|
||||
gateway.NetID = "skynet"
|
||||
deleteAllNodes()
|
||||
testnode := createTestNode()
|
||||
gateway.NodeID = testnode.ID
|
||||
gateway.NodeID = testnode.ID.String()
|
||||
|
||||
node, err := logic.CreateEgressGateway(gateway)
|
||||
t.Log(node)
|
||||
assert.Nil(t, err)
|
||||
assert.Contains(t, node.PostUp, "-j MASQUERADE")
|
||||
assert.Contains(t, node.PostDown, "-j MASQUERADE")
|
||||
assert.Equal(t, "yes", node.IsEgressGateway)
|
||||
assert.Equal(t, true, node.IsEgressGateway)
|
||||
assert.Equal(t, gateway.Ranges, node.EgressGatewayRanges)
|
||||
})
|
||||
|
||||
@@ -89,31 +87,27 @@ func TestDeleteEgressGateway(t *testing.T) {
|
||||
gateway.Interface = "eth0"
|
||||
gateway.Ranges = []string{"10.100.100.0/24"}
|
||||
gateway.NetID = "skynet"
|
||||
gateway.NodeID = testnode.ID
|
||||
gateway.NodeID = testnode.ID.String()
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
node, err := logic.CreateEgressGateway(gateway)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "yes", node.IsEgressGateway)
|
||||
assert.Equal(t, true, node.IsEgressGateway)
|
||||
assert.Equal(t, []string{"10.100.100.0/24"}, node.EgressGatewayRanges)
|
||||
node, err = logic.DeleteEgressGateway(gateway.NetID, gateway.NodeID)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "no", node.IsEgressGateway)
|
||||
assert.Equal(t, false, node.IsEgressGateway)
|
||||
assert.Equal(t, []string([]string{}), node.EgressGatewayRanges)
|
||||
assert.Equal(t, "", node.PostUp)
|
||||
assert.Equal(t, "", node.PostDown)
|
||||
})
|
||||
t.Run("NotGateway", func(t *testing.T) {
|
||||
node, err := logic.DeleteEgressGateway(gateway.NetID, gateway.NodeID)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "no", node.IsEgressGateway)
|
||||
assert.Equal(t, false, node.IsEgressGateway)
|
||||
assert.Equal(t, []string([]string{}), node.EgressGatewayRanges)
|
||||
assert.Equal(t, "", node.PostUp)
|
||||
assert.Equal(t, "", node.PostDown)
|
||||
})
|
||||
t.Run("BadNode", func(t *testing.T) {
|
||||
node, err := logic.DeleteEgressGateway(gateway.NetID, "01:02:03")
|
||||
assert.EqualError(t, err, "no result found")
|
||||
assert.Equal(t, models.LegacyNode{}, node)
|
||||
assert.Equal(t, models.Node{}, node)
|
||||
deleteAllNodes()
|
||||
})
|
||||
}
|
||||
@@ -140,23 +134,7 @@ func TestGetNetworkNodes(t *testing.T) {
|
||||
})
|
||||
|
||||
}
|
||||
func TestUncordonNode(t *testing.T) {
|
||||
database.InitializeDatabase()
|
||||
deleteAllNetworks()
|
||||
createNet()
|
||||
node := createTestNode()
|
||||
t.Run("BadID", func(t *testing.T) {
|
||||
resp, err := logic.UncordonNode("blahblah")
|
||||
assert.Equal(t, models.LegacyNode{}, resp)
|
||||
assert.EqualError(t, err, "no result found")
|
||||
})
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
resp, err := logic.UncordonNode(node.ID)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "no", resp.IsPending)
|
||||
})
|
||||
|
||||
}
|
||||
func TestValidateEgressGateway(t *testing.T) {
|
||||
var gateway models.EgressGatewayRequest
|
||||
t.Run("EmptyRange", func(t *testing.T) {
|
||||
@@ -181,66 +159,73 @@ func TestValidateEgressGateway(t *testing.T) {
|
||||
|
||||
func TestNodeACLs(t *testing.T) {
|
||||
deleteAllNodes()
|
||||
node1 := models.LegacyNode{PublicKey: "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Name: "testnode", Endpoint: "10.0.0.50", MacAddress: "01:02:03:04:05:06", Password: "password", Network: "skynet", OS: "linux"}
|
||||
node2 := models.LegacyNode{PublicKey: "DM5qhLAE20FG7BbfBCger+Ac9D2NDOwCtY1rbYDXf14=", Name: "testnode", Endpoint: "10.0.0.100", MacAddress: "01:02:03:04:05:07", Password: "password", Network: "skynet", OS: "linux"}
|
||||
logic.CreateNode(&node1)
|
||||
logic.CreateNode(&node2)
|
||||
node1 := createNodeWithParams("", "10.0.0.50/32")
|
||||
node2 := createNodeWithParams("", "10.0.0.100/32")
|
||||
logic.AssociateNodeToHost(node1, &linuxHost)
|
||||
logic.AssociateNodeToHost(node2, &linuxHost)
|
||||
t.Run("acls not present", func(t *testing.T) {
|
||||
currentACL, err := nodeacls.FetchAllACLs(nodeacls.NetworkID(node1.Network))
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, currentACL)
|
||||
node1ACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(node1.Network), nodeacls.NodeID(node1.ID))
|
||||
node1ACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(node1.Network), nodeacls.NodeID(node1.ID.String()))
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, node1ACL)
|
||||
assert.Equal(t, acls.Allowed, node1ACL[acls.AclID(node2.ID)])
|
||||
assert.Equal(t, acls.Allowed, node1ACL[acls.AclID(node2.ID.String())])
|
||||
})
|
||||
t.Run("node acls exists after creates", func(t *testing.T) {
|
||||
node1ACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(node1.Network), nodeacls.NodeID(node1.ID))
|
||||
node1ACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(node1.Network), nodeacls.NodeID(node1.ID.String()))
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, node1ACL)
|
||||
node2ACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(node2.Network), nodeacls.NodeID(node2.ID))
|
||||
node2ACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(node2.Network), nodeacls.NodeID(node2.ID.String()))
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, node2ACL)
|
||||
assert.Equal(t, acls.Allowed, node2ACL[acls.AclID(node1.ID)])
|
||||
assert.Equal(t, acls.Allowed, node2ACL[acls.AclID(node1.ID.String())])
|
||||
})
|
||||
t.Run("node acls correct after fetch", func(t *testing.T) {
|
||||
node1ACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(node1.Network), nodeacls.NodeID(node1.ID))
|
||||
node1ACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(node1.Network), nodeacls.NodeID(node1.ID.String()))
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, acls.Allowed, node1ACL[acls.AclID(node2.ID)])
|
||||
assert.Equal(t, acls.Allowed, node1ACL[acls.AclID(node2.ID.String())])
|
||||
})
|
||||
t.Run("node acls correct after modify", func(t *testing.T) {
|
||||
node1ACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(node1.Network), nodeacls.NodeID(node1.ID))
|
||||
node1ACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(node1.Network), nodeacls.NodeID(node1.ID.String()))
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, node1ACL)
|
||||
node2ACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(node2.Network), nodeacls.NodeID(node2.ID))
|
||||
node2ACL, err := nodeacls.FetchNodeACL(nodeacls.NetworkID(node2.Network), nodeacls.NodeID(node2.ID.String()))
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, node2ACL)
|
||||
currentACL, err := nodeacls.DisallowNodes(nodeacls.NetworkID(node1.Network), nodeacls.NodeID(node1.ID), nodeacls.NodeID(node2.ID))
|
||||
currentACL, err := nodeacls.DisallowNodes(nodeacls.NetworkID(node1.Network), nodeacls.NodeID(node1.ID.String()), nodeacls.NodeID(node2.ID.String()))
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, acls.NotAllowed, currentACL[acls.AclID(node1.ID)][acls.AclID(node2.ID)])
|
||||
assert.Equal(t, acls.NotAllowed, currentACL[acls.AclID(node2.ID)][acls.AclID(node1.ID)])
|
||||
assert.Equal(t, acls.NotAllowed, currentACL[acls.AclID(node1.ID.String())][acls.AclID(node2.ID.String())])
|
||||
assert.Equal(t, acls.NotAllowed, currentACL[acls.AclID(node2.ID.String())][acls.AclID(node1.ID.String())])
|
||||
currentACL.Save(acls.ContainerID(node1.Network))
|
||||
})
|
||||
t.Run("node acls correct after add new node not allowed", func(t *testing.T) {
|
||||
node3 := models.LegacyNode{PublicKey: "this-is-not-valid", Name: "testnode3", Endpoint: "10.0.0.100", MacAddress: "01:02:03:04:05:07", Password: "password", Network: "skynet", OS: "linux"}
|
||||
logic.CreateNode(&node3)
|
||||
var currentACL, err = nodeacls.FetchAllACLs(nodeacls.NetworkID(node3.Network))
|
||||
node3 := createNodeWithParams("", "10.0.0.100/32")
|
||||
createNodeHosts()
|
||||
n, e := logic.GetNetwork(node3.Network)
|
||||
assert.Nil(t, e)
|
||||
n.DefaultACL = "no"
|
||||
e = logic.SaveNetwork(&n)
|
||||
assert.Nil(t, e)
|
||||
err := logic.AssociateNodeToHost(node3, &linuxHost)
|
||||
assert.Nil(t, err)
|
||||
currentACL, err := nodeacls.FetchAllACLs(nodeacls.NetworkID(node3.Network))
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, currentACL)
|
||||
assert.Equal(t, acls.NotPresent, currentACL[acls.AclID(node1.ID)][acls.AclID(node3.ID)])
|
||||
nodeACL, err := nodeacls.CreateNodeACL(nodeacls.NetworkID(node3.Network), nodeacls.NodeID(node3.ID), acls.NotAllowed)
|
||||
assert.Equal(t, acls.NotAllowed, currentACL[acls.AclID(node1.ID.String())][acls.AclID(node3.ID.String())])
|
||||
nodeACL, err := nodeacls.CreateNodeACL(nodeacls.NetworkID(node3.Network), nodeacls.NodeID(node3.ID.String()), acls.NotAllowed)
|
||||
assert.Nil(t, err)
|
||||
nodeACL.Save(acls.ContainerID(node3.Network), acls.AclID(node3.ID))
|
||||
nodeACL.Save(acls.ContainerID(node3.Network), acls.AclID(node3.ID.String()))
|
||||
currentACL, err = nodeacls.FetchAllACLs(nodeacls.NetworkID(node3.Network))
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, acls.NotAllowed, currentACL[acls.AclID(node1.ID)][acls.AclID(node3.ID)])
|
||||
assert.Equal(t, acls.NotAllowed, currentACL[acls.AclID(node2.ID)][acls.AclID(node3.ID)])
|
||||
assert.Equal(t, acls.NotAllowed, currentACL[acls.AclID(node1.ID.String())][acls.AclID(node3.ID.String())])
|
||||
assert.Equal(t, acls.NotAllowed, currentACL[acls.AclID(node2.ID.String())][acls.AclID(node3.ID.String())])
|
||||
})
|
||||
t.Run("node acls removed", func(t *testing.T) {
|
||||
retNetworkACL, err := nodeacls.RemoveNodeACL(nodeacls.NetworkID(node1.Network), nodeacls.NodeID(node1.ID))
|
||||
retNetworkACL, err := nodeacls.RemoveNodeACL(nodeacls.NetworkID(node1.Network), nodeacls.NodeID(node1.ID.String()))
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, retNetworkACL)
|
||||
assert.Equal(t, acls.NotPresent, retNetworkACL[acls.AclID(node2.ID)][acls.AclID(node1.ID)])
|
||||
assert.Equal(t, acls.NotPresent, retNetworkACL[acls.AclID(node2.ID.String())][acls.AclID(node1.ID.String())])
|
||||
})
|
||||
deleteAllNodes()
|
||||
}
|
||||
@@ -249,8 +234,51 @@ func deleteAllNodes() {
|
||||
database.DeleteAllRecords(database.NODES_TABLE_NAME)
|
||||
}
|
||||
|
||||
func createTestNode() *models.LegacyNode {
|
||||
createnode := models.LegacyNode{PublicKey: "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Name: "testnode", Endpoint: "10.0.0.1", MacAddress: "01:02:03:04:05:06", Password: "password", Network: "skynet", OS: "linux"}
|
||||
logic.CreateNode(&createnode)
|
||||
func createTestNode() *models.Node {
|
||||
createNodeHosts()
|
||||
n := createNodeWithParams("skynet", "")
|
||||
_ = logic.AssociateNodeToHost(n, &linuxHost)
|
||||
return n
|
||||
}
|
||||
|
||||
func createNodeWithParams(network, address string) *models.Node {
|
||||
_, ipnet, _ := net.ParseCIDR("10.0.0.1/32")
|
||||
tmpCNode := models.CommonNode{
|
||||
ID: uuid.New(),
|
||||
Network: "skynet",
|
||||
Address: *ipnet,
|
||||
DNSOn: true,
|
||||
}
|
||||
if len(network) > 0 {
|
||||
tmpCNode.Network = network
|
||||
}
|
||||
if len(address) > 0 {
|
||||
_, ipnet2, _ := net.ParseCIDR(address)
|
||||
tmpCNode.Address = *ipnet2
|
||||
}
|
||||
createnode := models.Node{
|
||||
CommonNode: tmpCNode,
|
||||
}
|
||||
return &createnode
|
||||
}
|
||||
|
||||
func createNodeHosts() {
|
||||
k, _ := wgtypes.ParseKey("DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=")
|
||||
linuxHost = models.Host{
|
||||
ID: uuid.New(),
|
||||
PublicKey: k.PublicKey(),
|
||||
HostPass: "password",
|
||||
OS: "linux",
|
||||
Name: "linuxhost",
|
||||
}
|
||||
_ = logic.CreateHost(&linuxHost)
|
||||
nonLinuxHost = models.Host{
|
||||
ID: uuid.New(),
|
||||
OS: "windows",
|
||||
PublicKey: k.PublicKey(),
|
||||
Name: "windowshost",
|
||||
HostPass: "password",
|
||||
}
|
||||
|
||||
_ = logic.CreateHost(&nonLinuxHost)
|
||||
}
|
||||
|
||||
1
dev.yaml
1
dev.yaml
@@ -32,7 +32,6 @@ server:
|
||||
frontendurl: ""
|
||||
displaykeys: ""
|
||||
azuretenant: ""
|
||||
rce: "off"
|
||||
telemetry: ""
|
||||
manageiptables: "off"
|
||||
portforwardservices: ""
|
||||
|
||||
@@ -23,6 +23,7 @@ func ResetFailover(network string) error {
|
||||
return err
|
||||
}
|
||||
for _, node := range nodes {
|
||||
node := node
|
||||
err = SetFailover(&node)
|
||||
if err != nil {
|
||||
logger.Log(2, "error setting failover for node", node.ID.String(), ":", err.Error())
|
||||
|
||||
6
go.mod
6
go.mod
@@ -20,7 +20,7 @@ require (
|
||||
golang.org/x/oauth2 v0.3.0
|
||||
golang.org/x/sys v0.3.0 // indirect
|
||||
golang.org/x/text v0.5.0 // indirect
|
||||
golang.zx2c4.com/wireguard v0.0.0-20220920152132-bb719d3a6e2c
|
||||
golang.zx2c4.com/wireguard v0.0.0-20220920152132-bb719d3a6e2c // indirect
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220324164955-056925b7df31
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
@@ -29,7 +29,7 @@ require (
|
||||
require (
|
||||
filippo.io/edwards25519 v1.0.0
|
||||
github.com/c-robinson/iplib v1.0.6
|
||||
github.com/go-ping/ping v1.1.0 // indirect
|
||||
github.com/go-ping/ping v1.1.0
|
||||
github.com/posthog/posthog-go v0.0.0-20211028072449-93c17c49e2b0
|
||||
)
|
||||
|
||||
@@ -37,13 +37,11 @@ require (
|
||||
github.com/coreos/go-oidc/v3 v3.5.0
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e
|
||||
gortc.io/stun v1.23.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/gravitl/netclient v0.0.0-20230114051017-65ecaeffca09
|
||||
github.com/guumaster/tablewriter v0.0.10
|
||||
github.com/matryer/is v1.4.0
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
|
||||
9
go.sum
9
go.sum
@@ -62,8 +62,6 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gravitl/netclient v0.0.0-20230114051017-65ecaeffca09 h1:T0gLl+i8whnrdwtW91R4u8x8bmqFVfPTU9WfBratkMc=
|
||||
github.com/gravitl/netclient v0.0.0-20230114051017-65ecaeffca09/go.mod h1:g3q+vhLySW/6smOsWsVy5LrxoW++f+kqiBAp9BM6sbY=
|
||||
github.com/guumaster/tablewriter v0.0.10 h1:A0HD94yMdt4usgxBjoEceNeE0XMJ027euoHAzsPqBQs=
|
||||
github.com/guumaster/tablewriter v0.0.10/go.mod h1:p4FRFhyfo0UD9ZLmMRbbJooTUsxo6b80qZTERVDWrH8=
|
||||
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
|
||||
@@ -76,8 +74,8 @@ github.com/josharian/native v1.0.0 h1:Ts/E8zCSEsG17dUqv7joXJFybuMLjQfWE04tsBODTx
|
||||
github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
@@ -119,16 +117,14 @@ github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rqlite/gorqlite v0.0.0-20210514125552-08ff1e76b22f h1:BSnJgAfHzEp7o8PYJ7YfwAVHhqu7BYUTggcn/LGlUWY=
|
||||
github.com/rqlite/gorqlite v0.0.0-20210514125552-08ff1e76b22f/go.mod h1:UW/gxgQwSePTvL1KA8QEHsXeYHP4xkoXgbDdN781p34=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
@@ -208,7 +204,6 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220207234003-57398862261d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
||||
@@ -40,10 +40,6 @@ func CreateAccessKey(accesskey models.AccessKey, network models.Network) (models
|
||||
return models.AccessKey{}, errors.New("duplicate AccessKey Name")
|
||||
}
|
||||
}
|
||||
privAddr := ""
|
||||
if network.IsLocal != "" {
|
||||
privAddr = network.LocalRange
|
||||
}
|
||||
|
||||
netID := network.NetID
|
||||
|
||||
@@ -52,7 +48,6 @@ func CreateAccessKey(accesskey models.AccessKey, network models.Network) (models
|
||||
accessToken.APIConnString = servercfg.GetAPIConnString()
|
||||
accessToken.ClientConfig.Network = netID
|
||||
accessToken.ClientConfig.Key = accesskey.Value
|
||||
accessToken.ClientConfig.LocalRange = privAddr
|
||||
|
||||
tokenjson, err := json.Marshal(accessToken)
|
||||
if err != nil {
|
||||
|
||||
39
logic/dns.go
39
logic/dns.go
@@ -74,14 +74,27 @@ func GetNodeDNS(network string) ([]models.DNSEntry, error) {
|
||||
}
|
||||
|
||||
for _, value := range collection {
|
||||
var entry models.DNSEntry
|
||||
var node models.Node
|
||||
if err = json.Unmarshal([]byte(value), &node); err != nil {
|
||||
continue
|
||||
}
|
||||
if err = json.Unmarshal([]byte(value), &entry); node.Network == network && err == nil {
|
||||
dns = append(dns, entry)
|
||||
if node.Network != network {
|
||||
continue
|
||||
}
|
||||
host, err := GetHost(node.HostID.String())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
var entry = models.DNSEntry{}
|
||||
entry.Name = host.Name
|
||||
entry.Network = network
|
||||
if node.Address.IP != nil {
|
||||
entry.Address = node.Address.IP.String()
|
||||
}
|
||||
if node.Address6.IP != nil {
|
||||
entry.Address6 = node.Address6.IP.String()
|
||||
}
|
||||
dns = append(dns, entry)
|
||||
}
|
||||
|
||||
return dns, nil
|
||||
@@ -220,9 +233,6 @@ func ValidateDNSUpdate(change models.DNSEntry, entry models.DNSEntry) error {
|
||||
})
|
||||
_ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
|
||||
_, err := GetParentNetwork(change.Network)
|
||||
if err != nil {
|
||||
logger.Log(0, err.Error())
|
||||
}
|
||||
return err == nil
|
||||
})
|
||||
|
||||
@@ -245,3 +255,20 @@ func DeleteDNS(domain string, network string) error {
|
||||
err = database.DeleteRecord(database.DNS_TABLE_NAME, key)
|
||||
return err
|
||||
}
|
||||
|
||||
// CreateDNS - creates a DNS entry
|
||||
func CreateDNS(entry models.DNSEntry) (models.DNSEntry, error) {
|
||||
|
||||
k, err := GetRecordKey(entry.Name, entry.Network)
|
||||
if err != nil {
|
||||
return models.DNSEntry{}, err
|
||||
}
|
||||
|
||||
data, err := json.Marshal(&entry)
|
||||
if err != nil {
|
||||
return models.DNSEntry{}, err
|
||||
}
|
||||
|
||||
err = database.Insert(k, string(data), database.DNS_TABLE_NAME)
|
||||
return entry, err
|
||||
}
|
||||
|
||||
@@ -138,12 +138,6 @@ func CreateExtClient(extclient *models.ExtClient) error {
|
||||
return err
|
||||
}
|
||||
extclient.Address = newAddress.String()
|
||||
|
||||
extclientInternalAddr, err := UniqueAddress(extclient.Network, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
extclient.InternalIPAddr = extclientInternalAddr.String()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,11 +148,6 @@ func CreateExtClient(extclient *models.ExtClient) error {
|
||||
return err
|
||||
}
|
||||
extclient.Address6 = addr6.String()
|
||||
extclientInternalAddr6, err := UniqueAddress6(extclient.Network, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
extclient.InternalIPAddr6 = extclientInternalAddr6.String()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
249
logic/gateway.go
249
logic/gateway.go
@@ -4,7 +4,6 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gravitl/netmaker/database"
|
||||
@@ -48,62 +47,6 @@ func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, erro
|
||||
node.EgressGatewayRanges = gateway.Ranges
|
||||
node.EgressGatewayNatEnabled = models.ParseBool(gateway.NatEnabled)
|
||||
node.EgressGatewayRequest = gateway // store entire request for use when preserving the egress gateway
|
||||
postUpCmd := ""
|
||||
postDownCmd := ""
|
||||
ipv4, ipv6 := getNetworkProtocols(gateway.Ranges)
|
||||
logger.Log(3, "creating egress gateway firewall in use is '", host.FirewallInUse, "'")
|
||||
iface := models.WIREGUARD_INTERFACE
|
||||
if host.OS == "linux" {
|
||||
switch host.FirewallInUse {
|
||||
case models.FIREWALL_NFTABLES:
|
||||
// nftables only supported on Linux
|
||||
// assumes chains eg FORWARD and postrouting already exist
|
||||
logger.Log(3, "creating egress gateway nftables is present")
|
||||
// down commands don't remove as removal of the rules leaves an empty chain while
|
||||
// removing the chain with rules in it would remove all rules in that section (not safe
|
||||
// if there are remaining rules on the host that need to stay). In practice the chain is removed
|
||||
// when non-empty even though the removal of a non-empty chain should not be possible per nftables wiki.
|
||||
postUpCmd, postDownCmd = firewallNFTCommandsCreateEgress(iface, gateway.Interface, gateway.Ranges, node.EgressGatewayNatEnabled, ipv4, ipv6)
|
||||
|
||||
default: // iptables assumed
|
||||
logger.Log(3, "creating egress gateway nftables is not present")
|
||||
postUpCmd, postDownCmd = firewallIPTablesCommandsCreateEgress(iface, gateway.Interface, node.EgressGatewayNatEnabled, ipv4, ipv6)
|
||||
}
|
||||
}
|
||||
if host.OS == "freebsd" {
|
||||
// spacing around ; is important for later parsing of postup/postdown in wireguard/common.go
|
||||
postUpCmd = "kldload ipfw ipfw_nat ; "
|
||||
postUpCmd += "ipfw disable one_pass ; "
|
||||
postUpCmd += "ipfw nat 1 config if " + gateway.Interface + " same_ports unreg_only reset ; "
|
||||
postUpCmd += "ipfw add 64000 reass all from any to any in ; "
|
||||
postUpCmd += "ipfw add 64000 nat 1 ip from any to any in via " + gateway.Interface + " ; "
|
||||
postUpCmd += "ipfw add 64000 check-state ; "
|
||||
postUpCmd += "ipfw add 64000 nat 1 ip from any to any out via " + gateway.Interface + " ; "
|
||||
postUpCmd += "ipfw add 65534 allow ip from any to any ; "
|
||||
postDownCmd = "ipfw delete 64000 ; "
|
||||
postDownCmd += "ipfw delete 65534 ; "
|
||||
postDownCmd += "kldunload ipfw_nat ipfw"
|
||||
|
||||
}
|
||||
if gateway.PostUp != "" {
|
||||
postUpCmd = gateway.PostUp
|
||||
}
|
||||
if gateway.PostDown != "" {
|
||||
postDownCmd = gateway.PostDown
|
||||
}
|
||||
if node.PostUp != "" {
|
||||
if !strings.Contains(node.PostUp, postUpCmd) {
|
||||
postUpCmd = node.PostUp + postUpCmd
|
||||
}
|
||||
}
|
||||
if node.PostDown != "" {
|
||||
if !strings.Contains(node.PostDown, postDownCmd) {
|
||||
postDownCmd = node.PostDown + postDownCmd
|
||||
}
|
||||
}
|
||||
|
||||
node.PostUp = postUpCmd
|
||||
node.PostDown = postDownCmd
|
||||
node.SetLastModified()
|
||||
nodeData, err := json.Marshal(&node)
|
||||
if err != nil {
|
||||
@@ -136,39 +79,9 @@ func DeleteEgressGateway(network, nodeid string) (models.Node, error) {
|
||||
if err != nil {
|
||||
return models.Node{}, err
|
||||
}
|
||||
host, err := GetHost(node.HostID.String())
|
||||
if err != nil {
|
||||
return models.Node{}, err
|
||||
|
||||
}
|
||||
node.IsEgressGateway = false
|
||||
node.EgressGatewayRanges = []string{}
|
||||
node.EgressGatewayRequest = models.EgressGatewayRequest{} // remove preserved request as the egress gateway is gone
|
||||
// needed in case we don't preserve a gateway (i.e., no ingress to preserve)
|
||||
node.PostUp = ""
|
||||
node.PostDown = ""
|
||||
cidrs := []string{}
|
||||
cidrs = append(cidrs, node.IngressGatewayRange)
|
||||
cidrs = append(cidrs, node.IngressGatewayRange6)
|
||||
ipv4, ipv6 := getNetworkProtocols(cidrs)
|
||||
logger.Log(3, "deleting egress gateway firewall in use is '", host.FirewallInUse, "'")
|
||||
if node.IsIngressGateway { // check if node is still an ingress gateway before completely deleting postdown/up rules
|
||||
// still have an ingress gateway so preserve it
|
||||
iface := models.WIREGUARD_INTERFACE
|
||||
if host.OS == "linux" {
|
||||
switch host.FirewallInUse {
|
||||
case models.FIREWALL_NFTABLES:
|
||||
// nftables only supported on Linux
|
||||
// assumes chains eg FORWARD and postrouting already exist
|
||||
logger.Log(3, "deleting egress gateway nftables is present")
|
||||
node.PostUp, node.PostDown = firewallNFTCommandsCreateIngress(iface)
|
||||
default:
|
||||
logger.Log(3, "deleting egress gateway nftables is not present")
|
||||
node.PostUp, node.PostDown = firewallIPTablesCommandsCreateIngress(iface, ipv4, ipv6)
|
||||
}
|
||||
}
|
||||
// no need to preserve ingress gateway on FreeBSD as ingress is not supported on that OS
|
||||
}
|
||||
node.SetLastModified()
|
||||
|
||||
data, err := json.Marshal(&node)
|
||||
@@ -184,7 +97,6 @@ func DeleteEgressGateway(network, nodeid string) (models.Node, error) {
|
||||
// CreateIngressGateway - creates an ingress gateway
|
||||
func CreateIngressGateway(netid string, nodeid string, failover bool) (models.Node, error) {
|
||||
|
||||
var postUpCmd, postDownCmd string
|
||||
node, err := GetNodeByID(nodeid)
|
||||
if err != nil {
|
||||
return models.Node{}, err
|
||||
@@ -193,6 +105,9 @@ func CreateIngressGateway(netid string, nodeid string, failover bool) (models.No
|
||||
if err != nil {
|
||||
return models.Node{}, err
|
||||
}
|
||||
if host.OS != "linux" {
|
||||
return models.Node{}, errors.New("ingress can only be created on linux based node")
|
||||
}
|
||||
if host.FirewallInUse == models.FIREWALL_NONE {
|
||||
return models.Node{}, errors.New("firewall is not supported for ingress gateways")
|
||||
}
|
||||
@@ -202,38 +117,9 @@ func CreateIngressGateway(netid string, nodeid string, failover bool) (models.No
|
||||
return models.Node{}, err
|
||||
}
|
||||
node.IsIngressGateway = true
|
||||
cidrs := []string{}
|
||||
cidrs = append(cidrs, network.AddressRange)
|
||||
cidrs = append(cidrs, network.AddressRange6)
|
||||
node.IngressGatewayRange = network.AddressRange
|
||||
node.IngressGatewayRange6 = network.AddressRange6
|
||||
ipv4, ipv6 := getNetworkProtocols(cidrs)
|
||||
logger.Log(3, "creating ingress gateway firewall in use is '", host.FirewallInUse, "'")
|
||||
iface := models.WIREGUARD_INTERFACE
|
||||
switch host.FirewallInUse {
|
||||
case models.FIREWALL_NFTABLES:
|
||||
// nftables only supported on Linux
|
||||
// assumes chains eg FORWARD and postrouting already exist
|
||||
logger.Log(3, "creating ingress gateway nftables is present")
|
||||
postUpCmd, postDownCmd = firewallNFTCommandsCreateIngress(iface)
|
||||
default:
|
||||
logger.Log(3, "creating ingress gateway using nftables is not present")
|
||||
postUpCmd, postDownCmd = firewallIPTablesCommandsCreateIngress(iface, ipv4, ipv6)
|
||||
}
|
||||
|
||||
if node.PostUp != "" {
|
||||
if !strings.Contains(node.PostUp, postUpCmd) {
|
||||
postUpCmd = node.PostUp + postUpCmd
|
||||
}
|
||||
}
|
||||
if node.PostDown != "" {
|
||||
if !strings.Contains(node.PostDown, postDownCmd) {
|
||||
postDownCmd = node.PostDown + postDownCmd
|
||||
}
|
||||
}
|
||||
node.SetLastModified()
|
||||
node.PostUp = postUpCmd
|
||||
node.PostDown = postDownCmd
|
||||
if failover && servercfg.Is_EE {
|
||||
node.Failover = true
|
||||
}
|
||||
@@ -274,10 +160,6 @@ func DeleteIngressGateway(networkName string, nodeid string) (models.Node, bool,
|
||||
node.IngressGatewayRange = ""
|
||||
node.Failover = false
|
||||
|
||||
// default to removing postup and postdown
|
||||
node.PostUp = ""
|
||||
node.PostDown = ""
|
||||
|
||||
//logger.Log(3, "deleting ingress gateway firewall in use is '", host.FirewallInUse, "' and isEgressGateway is", node.IsEgressGateway)
|
||||
if node.EgressGatewayRequest.NodeID != "" {
|
||||
_, err := CreateEgressGateway(node.EgressGatewayRequest)
|
||||
@@ -315,128 +197,3 @@ func DeleteGatewayExtClients(gatewayID string, networkName string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// firewallNFTCommandsCreateIngress - used to centralize firewall command maintenance for creating an ingress gateway using the nftables firewall.
|
||||
func firewallNFTCommandsCreateIngress(networkInterface string) (string, string) {
|
||||
// spacing around ; is important for later parsing of postup/postdown in wireguard/common.go
|
||||
postUp := "nft add table ip filter ; "
|
||||
postUp += "nft add chain ip filter FORWARD ; "
|
||||
postUp += "nft add rule ip filter FORWARD iifname " + networkInterface + " counter accept ; "
|
||||
postUp += "nft add rule ip filter FORWARD oifname " + networkInterface + " counter accept ; "
|
||||
postUp += "nft add table nat ; "
|
||||
postUp += "nft add chain nat postrouting ; "
|
||||
postUp += "nft add rule ip nat postrouting oifname " + networkInterface + " counter masquerade ; "
|
||||
|
||||
// doesn't remove potentially empty tables or chains
|
||||
postDown := "nft flush table filter ; "
|
||||
postDown += "nft flush table nat ; "
|
||||
|
||||
return postUp, postDown
|
||||
}
|
||||
|
||||
// firewallNFTCommandsCreateEgress - used to centralize firewall command maintenance for creating an egress gateway using the nftables firewall.
|
||||
func firewallNFTCommandsCreateEgress(networkInterface string, gatewayInterface string, gatewayranges []string, egressNatEnabled bool, ipv4, ipv6 bool) (string, string) {
|
||||
// spacing around ; is important for later parsing of postup/postdown in wireguard/common.go
|
||||
postUp := ""
|
||||
postDown := ""
|
||||
if ipv4 {
|
||||
postUp += "nft add table ip filter ; "
|
||||
postUp += "nft add chain ip filter forward ; "
|
||||
postUp += "nft add rule filter forward ct state related,established accept ; "
|
||||
postUp += "nft add rule ip filter forward iifname " + networkInterface + " accept ; "
|
||||
postUp += "nft add rule ip filter forward oifname " + networkInterface + " accept ; "
|
||||
postUp += "nft add table nat ; "
|
||||
postUp += "nft 'add chain ip nat prerouting { type nat hook prerouting priority 0 ;}' ; "
|
||||
postUp += "nft 'add chain ip nat postrouting { type nat hook postrouting priority 0 ;}' ; "
|
||||
|
||||
postDown += "nft flush table filter ; "
|
||||
|
||||
if egressNatEnabled {
|
||||
postUp += "nft add table nat ; "
|
||||
postUp += "nft add chain nat postrouting ; "
|
||||
postUp += "nft add rule ip nat postrouting oifname " + gatewayInterface + " counter masquerade ; "
|
||||
|
||||
postDown += "nft flush table nat ; "
|
||||
}
|
||||
}
|
||||
if ipv6 {
|
||||
postUp += "nft add table ip6 filter ; "
|
||||
postUp += "nft add chain ip6 filter forward ; "
|
||||
postUp += "nft add rule ip6 filter forward ct state related,established accept ; "
|
||||
postUp += "nft add rule ip6 filter forward iifname " + networkInterface + " accept ; "
|
||||
postUp += "nft add rule ip6 filter forward oifname " + networkInterface + " accept ; "
|
||||
|
||||
postDown += "nft flush table ip6 filter ; "
|
||||
|
||||
if egressNatEnabled {
|
||||
postUp += "nft add table ip6 nat ; "
|
||||
postUp += "nft 'add chain ip6 nat prerouting { type nat hook prerouting priority 0 ;}' ; "
|
||||
postUp += "nft 'add chain ip6 nat postrouting { type nat hook postrouting priority 0 ;}' ; "
|
||||
postUp += "nft add rule ip6 nat postrouting oifname " + gatewayInterface + " masquerade ; "
|
||||
|
||||
postDown += "nft flush table ip6 nat ; "
|
||||
}
|
||||
}
|
||||
|
||||
return postUp, postDown
|
||||
}
|
||||
|
||||
// firewallIPTablesCommandsCreateIngress - used to centralize firewall command maintenance for creating an ingress gateway using the iptables firewall.
|
||||
func firewallIPTablesCommandsCreateIngress(networkInterface string, ipv4, ipv6 bool) (string, string) {
|
||||
postUp := ""
|
||||
postDown := ""
|
||||
if ipv4 {
|
||||
// spacing around ; is important for later parsing of postup/postdown in wireguard/common.go
|
||||
postUp += "iptables -A FORWARD -i " + networkInterface + " -j ACCEPT ; "
|
||||
postUp += "iptables -A FORWARD -o " + networkInterface + " -j ACCEPT ; "
|
||||
postUp += "iptables -t nat -A POSTROUTING -o " + networkInterface + " -j MASQUERADE ; "
|
||||
|
||||
// doesn't remove potentially empty tables or chains
|
||||
postDown += "iptables -D FORWARD -i " + networkInterface + " -j ACCEPT ; "
|
||||
postDown += "iptables -D FORWARD -o " + networkInterface + " -j ACCEPT ; "
|
||||
postDown += "iptables -t nat -D POSTROUTING -o " + networkInterface + " -j MASQUERADE ; "
|
||||
}
|
||||
if ipv6 {
|
||||
// spacing around ; is important for later parsing of postup/postdown in wireguard/common.go
|
||||
postUp += "ip6tables -A FORWARD -i " + networkInterface + " -j ACCEPT ; "
|
||||
postUp += "ip6tables -A FORWARD -o " + networkInterface + " -j ACCEPT ; "
|
||||
postUp += "ip6tables -t nat -A POSTROUTING -o " + networkInterface + " -j MASQUERADE ; "
|
||||
|
||||
// doesn't remove potentially empty tables or chains
|
||||
postDown += "ip6tables -D FORWARD -i " + networkInterface + " -j ACCEPT ; "
|
||||
postDown += "ip6tables -D FORWARD -o " + networkInterface + " -j ACCEPT ; "
|
||||
postDown += "ip6tables -t nat -D POSTROUTING -o " + networkInterface + " -j MASQUERADE ; "
|
||||
}
|
||||
return postUp, postDown
|
||||
}
|
||||
|
||||
// firewallIPTablesCommandsCreateEgress - used to centralize firewall command maintenance for creating an egress gateway using the iptables firewall.
|
||||
func firewallIPTablesCommandsCreateEgress(networkInterface string, gatewayInterface string, egressNatEnabled bool, ipv4, ipv6 bool) (string, string) {
|
||||
// spacing around ; is important for later parsing of postup/postdown in wireguard/common.go
|
||||
postUp := ""
|
||||
postDown := ""
|
||||
if ipv4 {
|
||||
postUp += "iptables -A FORWARD -i " + networkInterface + " -j ACCEPT ; "
|
||||
postUp += "iptables -A FORWARD -o " + networkInterface + " -j ACCEPT ; "
|
||||
postDown += "iptables -D FORWARD -i " + networkInterface + " -j ACCEPT ; "
|
||||
postDown += "iptables -D FORWARD -o " + networkInterface + " -j ACCEPT ; "
|
||||
|
||||
if egressNatEnabled {
|
||||
postUp += "iptables -t nat -A POSTROUTING -o " + gatewayInterface + " -j MASQUERADE ; "
|
||||
postDown += "iptables -t nat -D POSTROUTING -o " + gatewayInterface + " -j MASQUERADE ; "
|
||||
}
|
||||
}
|
||||
if ipv6 {
|
||||
postUp += "ip6tables -A FORWARD -i " + networkInterface + " -j ACCEPT ; "
|
||||
postUp += "ip6tables -A FORWARD -o " + networkInterface + " -j ACCEPT ; "
|
||||
postDown += "ip6tables -D FORWARD -i " + networkInterface + " -j ACCEPT ; "
|
||||
postDown += "ip6tables -D FORWARD -o " + networkInterface + " -j ACCEPT ; "
|
||||
|
||||
if egressNatEnabled {
|
||||
postUp += "ip6tables -t nat -A POSTROUTING -o " + gatewayInterface + " -j MASQUERADE ; "
|
||||
postDown += "ip6tables -t nat -D POSTROUTING -o " + gatewayInterface + " -j MASQUERADE ; "
|
||||
}
|
||||
}
|
||||
return postUp, postDown
|
||||
|
||||
}
|
||||
|
||||
62
logic/host_test.go
Normal file
62
logic/host_test.go
Normal 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)
|
||||
})
|
||||
}
|
||||
@@ -20,6 +20,11 @@ var (
|
||||
ErrInvalidHostID error = errors.New("invalid host id")
|
||||
)
|
||||
|
||||
const (
|
||||
maxPort = 1<<16 - 1
|
||||
minPort = 1025
|
||||
)
|
||||
|
||||
// GetAllHosts - returns all hosts in flat list or error
|
||||
func GetAllHosts() ([]models.Host, error) {
|
||||
currHostMap, err := GetHostsMap()
|
||||
@@ -117,10 +122,6 @@ func UpdateHost(newHost, currentHost *models.Host) {
|
||||
newHost.Name = currentHost.Name
|
||||
}
|
||||
|
||||
if newHost.LocalRange.String() != currentHost.LocalRange.String() {
|
||||
newHost.LocalRange = currentHost.LocalRange
|
||||
}
|
||||
|
||||
if newHost.MTU == 0 {
|
||||
newHost.MTU = currentHost.MTU
|
||||
}
|
||||
@@ -132,6 +133,42 @@ func UpdateHost(newHost, currentHost *models.Host) {
|
||||
if newHost.ProxyListenPort == 0 {
|
||||
newHost.ProxyListenPort = currentHost.ProxyListenPort
|
||||
}
|
||||
newHost.PublicListenPort = currentHost.PublicListenPort
|
||||
|
||||
}
|
||||
|
||||
// UpdateHostFromClient - used for updating host on server with update recieved from client
|
||||
func UpdateHostFromClient(newHost, currHost *models.Host) (sendPeerUpdate bool) {
|
||||
|
||||
if newHost.ListenPort != 0 && currHost.ListenPort != newHost.ListenPort {
|
||||
currHost.ListenPort = newHost.ListenPort
|
||||
sendPeerUpdate = true
|
||||
}
|
||||
if newHost.ProxyListenPort != 0 && currHost.ProxyListenPort != newHost.ProxyListenPort {
|
||||
currHost.ProxyListenPort = newHost.ProxyListenPort
|
||||
sendPeerUpdate = true
|
||||
}
|
||||
if newHost.PublicListenPort != 0 && currHost.PublicListenPort != newHost.PublicListenPort {
|
||||
currHost.PublicListenPort = newHost.PublicListenPort
|
||||
sendPeerUpdate = true
|
||||
}
|
||||
if currHost.ProxyEnabled != newHost.ProxyEnabled {
|
||||
currHost.ProxyEnabled = newHost.ProxyEnabled
|
||||
sendPeerUpdate = true
|
||||
}
|
||||
if currHost.EndpointIP.String() != newHost.EndpointIP.String() {
|
||||
currHost.EndpointIP = newHost.EndpointIP
|
||||
sendPeerUpdate = true
|
||||
}
|
||||
currHost.DaemonInstalled = newHost.DaemonInstalled
|
||||
currHost.Debug = newHost.Debug
|
||||
currHost.Verbosity = newHost.Verbosity
|
||||
currHost.Version = newHost.Version
|
||||
if newHost.Name != "" {
|
||||
currHost.Name = newHost.Name
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// UpsertHost - upserts into DB a given host model, does not check for existence*
|
||||
@@ -328,3 +365,47 @@ func GetRelatedHosts(hostID string) []models.Host {
|
||||
}
|
||||
return relatedHosts
|
||||
}
|
||||
|
||||
// CheckHostPort checks host endpoints to ensures that hosts on the same server
|
||||
// with the same endpoint have different listen ports
|
||||
// in the case of 64535 hosts or more with same endpoint, ports will not be changed
|
||||
func CheckHostPorts(h *models.Host) {
|
||||
portsInUse := make(map[int]bool)
|
||||
hosts, err := GetAllHosts()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, host := range hosts {
|
||||
if host.ID == h.ID {
|
||||
//skip self
|
||||
continue
|
||||
}
|
||||
if !host.EndpointIP.Equal(h.EndpointIP) {
|
||||
continue
|
||||
}
|
||||
portsInUse[host.ListenPort] = true
|
||||
portsInUse[host.ProxyListenPort] = true
|
||||
}
|
||||
// iterate until port is not found or max iteration is reached
|
||||
for i := 0; portsInUse[h.ListenPort] && i < maxPort-minPort+1; i++ {
|
||||
updatePort(&h.ListenPort)
|
||||
}
|
||||
// allocate h.ListenPort so it is unavailable to h.ProxyListenPort
|
||||
portsInUse[h.ListenPort] = true
|
||||
for i := 0; portsInUse[h.ProxyListenPort] && i < maxPort-minPort+1; i++ {
|
||||
updatePort(&h.ProxyListenPort)
|
||||
}
|
||||
}
|
||||
|
||||
// HostExists - checks if given host already exists
|
||||
func HostExists(h *models.Host) bool {
|
||||
_, err := GetHost(h.ID.String())
|
||||
return (err != nil && !database.IsEmptyRecord(err)) || (err == nil)
|
||||
}
|
||||
|
||||
func updatePort(p *int) {
|
||||
*p++
|
||||
if *p > maxPort {
|
||||
*p = minPort
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ func VerifyUserToken(tokenString string) (username string, networks []string, is
|
||||
}
|
||||
|
||||
// VerifyToken - [nodes] Only
|
||||
func VerifyToken(tokenString string) (nodeID string, mac string, network string, err error) {
|
||||
func VerifyToken(tokenString string) (hostID string, mac string, network string, err error) {
|
||||
claims := &models.Claims{}
|
||||
|
||||
// this may be a stupid way of serving up a master key
|
||||
|
||||
@@ -3,9 +3,9 @@ package metrics
|
||||
import (
|
||||
"time"
|
||||
|
||||
proxy_metrics "github.com/gravitl/netclient/nmproxy/metrics"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
proxy_metrics "github.com/gravitl/netmaker/metrics"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"golang.zx2c4.com/wireguard/wgctrl"
|
||||
)
|
||||
|
||||
@@ -237,12 +237,12 @@ func IsIPUnique(network string, ip string, tableName string, isIpv6 bool) bool {
|
||||
continue
|
||||
}
|
||||
if isIpv6 {
|
||||
if (extClient.Address6 == ip || extClient.InternalIPAddr6 == ip) && extClient.Network == network {
|
||||
if (extClient.Address6 == ip) && extClient.Network == network {
|
||||
return false
|
||||
}
|
||||
|
||||
} else {
|
||||
if (extClient.Address == ip || extClient.InternalIPAddr == ip) && extClient.Network == network {
|
||||
if (extClient.Address == ip) && extClient.Network == network {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -298,60 +298,6 @@ func UniqueAddress6(networkName string, reverse bool) (net.IP, error) {
|
||||
return add, errors.New("ERROR: No unique IPv6 addresses available. Check network subnet")
|
||||
}
|
||||
|
||||
// GetLocalIP - gets the local ip
|
||||
func GetLocalIP(node models.Node) string {
|
||||
var local string
|
||||
ifaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return local
|
||||
}
|
||||
host, err := GetHost(node.HostID.String())
|
||||
if err != nil {
|
||||
return local
|
||||
}
|
||||
localrange := host.LocalRange
|
||||
found := false
|
||||
for _, i := range ifaces {
|
||||
if i.Flags&net.FlagUp == 0 {
|
||||
continue // interface down
|
||||
}
|
||||
if i.Flags&net.FlagLoopback != 0 {
|
||||
continue // loopback interface
|
||||
}
|
||||
addrs, err := i.Addrs()
|
||||
if err != nil {
|
||||
return local
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
var ip net.IP
|
||||
switch v := addr.(type) {
|
||||
case *net.IPNet:
|
||||
if !found {
|
||||
ip = v.IP
|
||||
local = ip.String()
|
||||
if node.IsLocal {
|
||||
found = localrange.Contains(ip)
|
||||
} else {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
case *net.IPAddr:
|
||||
if !found {
|
||||
ip = v.IP
|
||||
local = ip.String()
|
||||
if node.IsLocal {
|
||||
found = localrange.Contains(ip)
|
||||
|
||||
} else {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return local
|
||||
}
|
||||
|
||||
// UpdateNetworkLocalAddresses - updates network localaddresses
|
||||
func UpdateNetworkLocalAddresses(networkName string) error {
|
||||
|
||||
@@ -517,14 +463,13 @@ func IsNetworkNameUnique(network *models.Network) (bool, error) {
|
||||
}
|
||||
|
||||
// UpdateNetwork - updates a network with another network's fields
|
||||
func UpdateNetwork(currentNetwork *models.Network, newNetwork *models.Network) (bool, bool, bool, bool, []string, []string, error) {
|
||||
func UpdateNetwork(currentNetwork *models.Network, newNetwork *models.Network) (bool, bool, bool, []string, []string, error) {
|
||||
if err := ValidateNetwork(newNetwork, true); err != nil {
|
||||
return false, false, false, false, nil, nil, err
|
||||
return false, false, false, nil, nil, err
|
||||
}
|
||||
if newNetwork.NetID == currentNetwork.NetID {
|
||||
hasrangeupdate4 := newNetwork.AddressRange != currentNetwork.AddressRange
|
||||
hasrangeupdate6 := newNetwork.AddressRange6 != currentNetwork.AddressRange6
|
||||
localrangeupdate := newNetwork.LocalRange != currentNetwork.LocalRange
|
||||
hasholepunchupdate := newNetwork.DefaultUDPHolePunch != currentNetwork.DefaultUDPHolePunch
|
||||
groupDelta := append(StringDifference(newNetwork.ProSettings.AllowedGroups, currentNetwork.ProSettings.AllowedGroups),
|
||||
StringDifference(currentNetwork.ProSettings.AllowedGroups, newNetwork.ProSettings.AllowedGroups)...)
|
||||
@@ -532,14 +477,14 @@ func UpdateNetwork(currentNetwork *models.Network, newNetwork *models.Network) (
|
||||
StringDifference(currentNetwork.ProSettings.AllowedUsers, newNetwork.ProSettings.AllowedUsers)...)
|
||||
data, err := json.Marshal(newNetwork)
|
||||
if err != nil {
|
||||
return false, false, false, false, nil, nil, err
|
||||
return false, false, false, nil, nil, err
|
||||
}
|
||||
newNetwork.SetNetworkLastModified()
|
||||
err = database.Insert(newNetwork.NetID, string(data), database.NETWORKS_TABLE_NAME)
|
||||
return hasrangeupdate4, hasrangeupdate6, localrangeupdate, hasholepunchupdate, groupDelta, userDelta, err
|
||||
return hasrangeupdate4, hasrangeupdate6, hasholepunchupdate, groupDelta, userDelta, err
|
||||
}
|
||||
// copy values
|
||||
return false, false, false, false, nil, nil, errors.New("failed to update network " + newNetwork.NetID + ", cannot change netid.")
|
||||
return false, false, false, nil, nil, errors.New("failed to update network " + newNetwork.NetID + ", cannot change netid.")
|
||||
}
|
||||
|
||||
// GetNetwork - gets a network from database
|
||||
|
||||
@@ -50,7 +50,7 @@ func GetNetworkNodes(network string) ([]models.Node, error) {
|
||||
func UpdateNode(currentNode *models.Node, newNode *models.Node) error {
|
||||
if newNode.Address.IP.String() != currentNode.Address.IP.String() {
|
||||
if network, err := GetParentNetwork(newNode.Network); err == nil {
|
||||
if !IsAddressInCIDR(newNode.Address.IP.String(), network.AddressRange) {
|
||||
if !IsAddressInCIDR(newNode.Address.IP, network.AddressRange) {
|
||||
return fmt.Errorf("invalid address provided; out of network range for node %s", newNode.ID)
|
||||
}
|
||||
}
|
||||
@@ -203,7 +203,7 @@ func GetAllNodes() ([]models.Node, error) {
|
||||
var node models.Node
|
||||
// ignore legacy nodes in database
|
||||
if err := json.Unmarshal([]byte(value), &node); err != nil {
|
||||
logger.Log(1, "legacy node detected: ", err.Error())
|
||||
logger.Log(3, "legacy node detected: ", err.Error())
|
||||
continue
|
||||
}
|
||||
// add node to our array
|
||||
@@ -239,7 +239,6 @@ func SetNodeDefaults(node *models.Node) {
|
||||
if err == nil {
|
||||
node.NetworkRange6 = *cidr
|
||||
}
|
||||
node.ExpirationDateTime = time.Now().Add(models.TEN_YEARS_IN_SECONDS)
|
||||
|
||||
if node.DefaultACL == "" {
|
||||
node.DefaultACL = parentNetwork.DefaultACL
|
||||
@@ -248,49 +247,10 @@ func SetNodeDefaults(node *models.Node) {
|
||||
if node.PersistentKeepalive == 0 {
|
||||
node.PersistentKeepalive = time.Second * time.Duration(parentNetwork.DefaultKeepalive)
|
||||
}
|
||||
if node.PostUp == "" {
|
||||
postup := parentNetwork.DefaultPostUp
|
||||
node.PostUp = postup
|
||||
}
|
||||
if node.PostDown == "" {
|
||||
postdown := parentNetwork.DefaultPostDown
|
||||
node.PostDown = postdown
|
||||
}
|
||||
// == Parent Network settings ==
|
||||
|
||||
// == node defaults if not set by parent ==
|
||||
///TODO ___ REVISIT ------
|
||||
///TODO ___ REVISIT ------
|
||||
///TODO ___ REVISIT ------
|
||||
///TODO ___ REVISIT ------
|
||||
///TODO ___ REVISIT ------
|
||||
//node.SetIPForwardingDefault()
|
||||
//node.SetDNSOnDefault()
|
||||
//node.SetIsLocalDefault()
|
||||
//node.SetLastModified()
|
||||
//node.SetDefaultName()
|
||||
//node.SetLastCheckIn()
|
||||
//node.SetLastPeerUpdate()
|
||||
//node.SetDefaultAction()
|
||||
//node.SetIsServerDefault()
|
||||
//node.SetIsStaticDefault()
|
||||
//node.SetDefaultEgressGateway()
|
||||
//node.SetDefaultIngressGateway()
|
||||
//node.SetDefaulIsPending()
|
||||
//node.SetDefaultMTU()
|
||||
//node.SetDefaultNFTablesPresent()
|
||||
//node.SetDefaultIsRelayed()
|
||||
//node.SetDefaultIsRelay()
|
||||
//node.SetDefaultIsDocker()
|
||||
//node.SetDefaultIsK8S()
|
||||
//node.SetDefaultIsHub()
|
||||
//node.SetDefaultConnected()
|
||||
//node.SetDefaultACL()
|
||||
//node.SetDefaultFailover()
|
||||
///TODO ___ REVISIT ------
|
||||
///TODO ___ REVISIT ------
|
||||
///TODO ___ REVISIT ------
|
||||
///TODO ___ REVISIT ------
|
||||
node.SetLastModified()
|
||||
node.SetLastCheckIn()
|
||||
node.SetDefaultConnected()
|
||||
node.SetExpirationDateTime()
|
||||
}
|
||||
|
||||
// GetRecordKey - get record key
|
||||
@@ -302,30 +262,6 @@ func GetRecordKey(id string, network string) (string, error) {
|
||||
return id + "###" + network, nil
|
||||
}
|
||||
|
||||
// GetNodeByMacAddress - gets a node by mac address
|
||||
func GetNodeByMacAddress(network string, macaddress string) (models.Node, error) {
|
||||
|
||||
var node models.Node
|
||||
|
||||
key, err := GetRecordKey(macaddress, network)
|
||||
if err != nil {
|
||||
return node, err
|
||||
}
|
||||
|
||||
record, err := database.FetchRecord(database.NODES_TABLE_NAME, key)
|
||||
if err != nil {
|
||||
return models.Node{}, err
|
||||
}
|
||||
|
||||
if err = json.Unmarshal([]byte(record), &node); err != nil {
|
||||
return models.Node{}, err
|
||||
}
|
||||
|
||||
SetNodeDefaults(&node)
|
||||
|
||||
return node, nil
|
||||
}
|
||||
|
||||
// GetNodesByAddress - gets a node by mac address
|
||||
func GetNodesByAddress(network string, addresses []string) ([]models.Node, error) {
|
||||
var nodes []models.Node
|
||||
|
||||
171
logic/peers.go
171
logic/peers.go
@@ -5,12 +5,12 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/netip"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
proxy_models "github.com/gravitl/netclient/nmproxy/models"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic/acls/nodeacls"
|
||||
@@ -28,10 +28,10 @@ import (
|
||||
// TODO ==========================
|
||||
// TODO ==========================
|
||||
// revisit this logic with new host/node models.
|
||||
func GetPeersForProxy(node *models.Node, onlyPeers bool) (proxy_models.ProxyManagerPayload, error) {
|
||||
proxyPayload := proxy_models.ProxyManagerPayload{}
|
||||
func GetPeersForProxy(node *models.Node, onlyPeers bool) (models.ProxyManagerPayload, error) {
|
||||
proxyPayload := models.ProxyManagerPayload{}
|
||||
var peers []wgtypes.PeerConfig
|
||||
peerConfMap := make(map[string]proxy_models.PeerConf)
|
||||
peerConfMap := make(map[string]models.PeerConf)
|
||||
var err error
|
||||
currentPeers, err := GetNetworkNodes(node.Network)
|
||||
if err != nil {
|
||||
@@ -70,8 +70,9 @@ func GetPeersForProxy(node *models.Node, onlyPeers bool) (proxy_models.ProxyMana
|
||||
logger.Log(1, "failed to relayed nodes: ", node.ID.String(), err.Error())
|
||||
proxyPayload.IsRelay = false
|
||||
} else {
|
||||
relayPeersMap := make(map[string]proxy_models.RelayedConf)
|
||||
relayPeersMap := make(map[string]models.RelayedConf)
|
||||
for _, relayedNode := range relayedNodes {
|
||||
relayedNode := relayedNode
|
||||
payload, err := GetPeersForProxy(&relayedNode, true)
|
||||
if err == nil {
|
||||
relayedHost, err := GetHost(relayedNode.HostID.String())
|
||||
@@ -80,7 +81,7 @@ func GetPeersForProxy(node *models.Node, onlyPeers bool) (proxy_models.ProxyMana
|
||||
}
|
||||
relayedEndpoint, udpErr := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", relayedHost.EndpointIP, host.ListenPort))
|
||||
if udpErr == nil {
|
||||
relayPeersMap[host.PublicKey.String()] = proxy_models.RelayedConf{
|
||||
relayPeersMap[host.PublicKey.String()] = models.RelayedConf{
|
||||
RelayedPeerEndpoint: relayedEndpoint,
|
||||
RelayedPeerPubKey: relayedHost.PublicKey.String(),
|
||||
Peers: payload.Peers,
|
||||
@@ -110,7 +111,7 @@ func GetPeersForProxy(node *models.Node, onlyPeers bool) (proxy_models.ProxyMana
|
||||
if proxyStatus {
|
||||
listenPort = host.ProxyListenPort
|
||||
if listenPort == 0 {
|
||||
listenPort = proxy_models.NmProxyPort
|
||||
listenPort = models.NmProxyPort
|
||||
}
|
||||
} else if listenPort == 0 {
|
||||
listenPort = host.ListenPort
|
||||
@@ -135,7 +136,7 @@ func GetPeersForProxy(node *models.Node, onlyPeers bool) (proxy_models.ProxyMana
|
||||
PersistentKeepaliveInterval: &keepalive,
|
||||
ReplaceAllowedIPs: true,
|
||||
})
|
||||
peerConfMap[host.PublicKey.String()] = proxy_models.PeerConf{
|
||||
peerConfMap[host.PublicKey.String()] = models.PeerConf{
|
||||
Address: net.ParseIP(peer.PrimaryAddress()),
|
||||
Proxy: proxyStatus,
|
||||
PublicListenPort: int32(listenPort),
|
||||
@@ -151,7 +152,7 @@ func GetPeersForProxy(node *models.Node, onlyPeers bool) (proxy_models.ProxyMana
|
||||
}
|
||||
relayTo, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", relayHost.EndpointIP, relayHost.ListenPort))
|
||||
if err == nil {
|
||||
peerConfMap[host.PublicKey.String()] = proxy_models.PeerConf{
|
||||
peerConfMap[host.PublicKey.String()] = models.PeerConf{
|
||||
|
||||
IsRelayed: true,
|
||||
RelayedTo: relayTo,
|
||||
@@ -192,11 +193,11 @@ func GetPeersForProxy(node *models.Node, onlyPeers bool) (proxy_models.ProxyMana
|
||||
}
|
||||
|
||||
// GetProxyUpdateForHost - gets the proxy update for host
|
||||
func GetProxyUpdateForHost(host *models.Host) (proxy_models.ProxyManagerPayload, error) {
|
||||
proxyPayload := proxy_models.ProxyManagerPayload{
|
||||
Action: proxy_models.ProxyUpdate,
|
||||
func GetProxyUpdateForHost(host *models.Host) (models.ProxyManagerPayload, error) {
|
||||
proxyPayload := models.ProxyManagerPayload{
|
||||
Action: models.ProxyUpdate,
|
||||
}
|
||||
peerConfMap := make(map[string]proxy_models.PeerConf)
|
||||
peerConfMap := make(map[string]models.PeerConf)
|
||||
if host.IsRelayed {
|
||||
relayHost, err := GetHost(host.RelayedBy)
|
||||
if err == nil {
|
||||
@@ -213,13 +214,14 @@ func GetProxyUpdateForHost(host *models.Host) (proxy_models.ProxyManagerPayload,
|
||||
}
|
||||
if host.IsRelay {
|
||||
relayedHosts := GetRelayedHosts(host)
|
||||
relayPeersMap := make(map[string]proxy_models.RelayedConf)
|
||||
relayPeersMap := make(map[string]models.RelayedConf)
|
||||
for _, relayedHost := range relayedHosts {
|
||||
relayedHost := relayedHost
|
||||
payload, err := GetPeerUpdateForHost(&relayedHost)
|
||||
if err == nil {
|
||||
relayedEndpoint, udpErr := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", relayedHost.EndpointIP, getPeerListenPort(&relayedHost)))
|
||||
if udpErr == nil {
|
||||
relayPeersMap[relayedHost.PublicKey.String()] = proxy_models.RelayedConf{
|
||||
relayPeersMap[relayedHost.PublicKey.String()] = models.RelayedConf{
|
||||
RelayedPeerEndpoint: relayedEndpoint,
|
||||
RelayedPeerPubKey: relayedHost.PublicKey.String(),
|
||||
Peers: payload.Peers,
|
||||
@@ -252,11 +254,10 @@ func GetProxyUpdateForHost(host *models.Host) (proxy_models.ProxyManagerPayload,
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
var currPeerConf proxy_models.PeerConf
|
||||
var currPeerConf models.PeerConf
|
||||
var found bool
|
||||
if currPeerConf, found = peerConfMap[peerHost.PublicKey.String()]; !found {
|
||||
currPeerConf = proxy_models.PeerConf{
|
||||
currPeerConf = models.PeerConf{
|
||||
Proxy: peerHost.ProxyEnabled,
|
||||
PublicListenPort: int32(getPeerListenPort(peerHost)),
|
||||
}
|
||||
@@ -299,12 +300,16 @@ func GetPeerUpdateForHost(host *models.Host) (models.HostPeerUpdate, error) {
|
||||
}
|
||||
hostPeerUpdate := models.HostPeerUpdate{
|
||||
Host: *host,
|
||||
Server: servercfg.GetServer(),
|
||||
Network: make(map[string]models.NetworkInfo),
|
||||
PeerIDs: make(models.HostPeerMap),
|
||||
ServerVersion: servercfg.GetVersion(),
|
||||
ServerAddrs: []models.ServerAddr{},
|
||||
IngressInfo: models.IngressInfo{
|
||||
ExtPeers: make(map[string]models.ExtClientInfo),
|
||||
},
|
||||
}
|
||||
log.Println("peer update for host ", host.ID.String())
|
||||
logger.Log(1, "peer update for host ", host.ID.String())
|
||||
peerIndexMap := make(map[string]int)
|
||||
for _, nodeID := range host.Nodes {
|
||||
node, err := GetNodeByID(nodeID)
|
||||
@@ -314,6 +319,7 @@ func GetPeerUpdateForHost(host *models.Host) (models.HostPeerUpdate, error) {
|
||||
if !node.Connected || node.Action == models.NODE_DELETE || node.PendingDelete {
|
||||
continue
|
||||
}
|
||||
|
||||
hostPeerUpdate.Network[node.Network] = models.NetworkInfo{
|
||||
DNS: getPeerDNS(node.Network),
|
||||
}
|
||||
@@ -322,9 +328,13 @@ func GetPeerUpdateForHost(host *models.Host) (models.HostPeerUpdate, error) {
|
||||
log.Println("no network nodes")
|
||||
return models.HostPeerUpdate{}, err
|
||||
}
|
||||
var extClientPeerMap map[string]models.PeerExtInfo
|
||||
if node.IsIngressGateway {
|
||||
extClientPeerMap = make(map[string]models.PeerExtInfo)
|
||||
}
|
||||
for _, peer := range currentPeers {
|
||||
if peer.ID == node.ID {
|
||||
log.Println("peer update, skipping self")
|
||||
logger.Log(2, "peer update, skipping self")
|
||||
//skip yourself
|
||||
|
||||
continue
|
||||
@@ -332,12 +342,12 @@ func GetPeerUpdateForHost(host *models.Host) (models.HostPeerUpdate, error) {
|
||||
var peerConfig wgtypes.PeerConfig
|
||||
peerHost, err := GetHost(peer.HostID.String())
|
||||
if err != nil {
|
||||
log.Println("no peer host", err)
|
||||
logger.Log(1, "no peer host", peer.HostID.String(), err.Error())
|
||||
return models.HostPeerUpdate{}, err
|
||||
}
|
||||
|
||||
if !peer.Connected {
|
||||
log.Println("peer update, skipping unconnected node")
|
||||
if !peer.Connected || peer.Action == models.NODE_DELETE || peer.PendingDelete {
|
||||
logger.Log(2, "peer update, skipping unconnected node", peer.ID.String())
|
||||
//skip unconnected nodes
|
||||
continue
|
||||
}
|
||||
@@ -383,6 +393,17 @@ func GetPeerUpdateForHost(host *models.Host) (models.HostPeerUpdate, error) {
|
||||
allowedips = append(allowedips, getEgressIPs(&node, &peer)...)
|
||||
}
|
||||
peerConfig.AllowedIPs = allowedips
|
||||
if node.IsIngressGateway {
|
||||
|
||||
extClientPeerMap[peerHost.PublicKey.String()] = models.PeerExtInfo{
|
||||
PeerAddr: net.IPNet{
|
||||
IP: net.ParseIP(peer.PrimaryAddress()),
|
||||
Mask: getCIDRMaskFromAddr(peer.PrimaryAddress()),
|
||||
},
|
||||
PeerKey: peerHost.PublicKey.String(),
|
||||
Allow: true,
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := hostPeerUpdate.PeerIDs[peerHost.PublicKey.String()]; !ok {
|
||||
hostPeerUpdate.PeerIDs[peerHost.PublicKey.String()] = make(map[string]models.IDandAddr)
|
||||
@@ -408,7 +429,7 @@ func GetPeerUpdateForHost(host *models.Host) (models.HostPeerUpdate, error) {
|
||||
|
||||
}
|
||||
if node.IsIngressGateway {
|
||||
extPeers, extPeerIDAndAddrs, err := getExtPeers(&node, true)
|
||||
extPeers, extPeerIDAndAddrs, err := getExtPeers(&node)
|
||||
if err == nil {
|
||||
hostPeerUpdate.Peers = append(hostPeerUpdate.Peers, extPeers...)
|
||||
for _, extPeerIdAndAddr := range extPeerIDAndAddrs {
|
||||
@@ -419,6 +440,19 @@ func GetPeerUpdateForHost(host *models.Host) (models.HostPeerUpdate, error) {
|
||||
Name: extPeerIdAndAddr.Name,
|
||||
Network: node.Network,
|
||||
}
|
||||
hostPeerUpdate.IngressInfo.ExtPeers[extPeerIdAndAddr.ID] = models.ExtClientInfo{
|
||||
Masquerade: true,
|
||||
IngGwAddr: net.IPNet{
|
||||
IP: net.ParseIP(node.PrimaryAddress()),
|
||||
Mask: getCIDRMaskFromAddr(node.PrimaryAddress()),
|
||||
},
|
||||
ExtPeerAddr: net.IPNet{
|
||||
IP: net.ParseIP(extPeerIdAndAddr.Address),
|
||||
Mask: getCIDRMaskFromAddr(extPeerIdAndAddr.Address),
|
||||
},
|
||||
ExtPeerKey: extPeerIdAndAddr.ID,
|
||||
Peers: extClientPeerMap,
|
||||
}
|
||||
}
|
||||
|
||||
} else if !database.IsEmptyRecord(err) {
|
||||
@@ -530,21 +564,21 @@ func GetPeerUpdate(node *models.Node, host *models.Host) (models.PeerUpdate, err
|
||||
return peerUpdate, nil
|
||||
}
|
||||
|
||||
func getRelayAllowedIPs(node, peer *models.Node) []net.IPNet {
|
||||
var allowedips []net.IPNet
|
||||
var allowedip net.IPNet
|
||||
for _, addr := range peer.RelayAddrs {
|
||||
if node.Address.IP.String() == addr {
|
||||
continue
|
||||
}
|
||||
if node.Address6.IP.String() == addr {
|
||||
continue
|
||||
}
|
||||
allowedip.IP = net.ParseIP(addr)
|
||||
allowedips = append(allowedips, allowedip)
|
||||
}
|
||||
return allowedips
|
||||
}
|
||||
// func getRelayAllowedIPs(node, peer *models.Node) []net.IPNet {
|
||||
// var allowedips []net.IPNet
|
||||
// var allowedip net.IPNet
|
||||
// for _, addr := range peer.RelayAddrs {
|
||||
// if node.Address.IP.String() == addr {
|
||||
// continue
|
||||
// }
|
||||
// if node.Address6.IP.String() == addr {
|
||||
// continue
|
||||
// }
|
||||
// allowedip.IP = net.ParseIP(addr)
|
||||
// allowedips = append(allowedips, allowedip)
|
||||
// }
|
||||
// return allowedips
|
||||
// }
|
||||
|
||||
// GetPeerUpdateLegacy - gets a wireguard peer config for each peer of a node
|
||||
func GetPeerUpdateLegacy(node *models.Node) (models.PeerUpdate, error) {
|
||||
@@ -699,7 +733,7 @@ func GetPeerUpdateLegacy(node *models.Node) (models.PeerUpdate, error) {
|
||||
|
||||
}
|
||||
if node.IsIngressGateway {
|
||||
extPeers, idsAndAddr, err := getExtPeers(node, true)
|
||||
extPeers, idsAndAddr, err := getExtPeers(node)
|
||||
if err == nil {
|
||||
peers = append(peers, extPeers...)
|
||||
for i := range idsAndAddr {
|
||||
@@ -722,7 +756,7 @@ func GetPeerUpdateLegacy(node *models.Node) (models.PeerUpdate, error) {
|
||||
return peerUpdate, nil
|
||||
}
|
||||
|
||||
func getExtPeers(node *models.Node, forIngressNode bool) ([]wgtypes.PeerConfig, []models.IDandAddr, error) {
|
||||
func getExtPeers(node *models.Node) ([]wgtypes.PeerConfig, []models.IDandAddr, error) {
|
||||
var peers []wgtypes.PeerConfig
|
||||
var idsAndAddr []models.IDandAddr
|
||||
extPeers, err := GetNetworkExtClients(node.Network)
|
||||
@@ -740,13 +774,14 @@ func getExtPeers(node *models.Node, forIngressNode bool) ([]wgtypes.PeerConfig,
|
||||
continue
|
||||
}
|
||||
|
||||
if host.PublicKey.String() == extPeer.PublicKey {
|
||||
if host.PublicKey.String() == extPeer.PublicKey ||
|
||||
extPeer.IngressGatewayID != node.ID.String() || !extPeer.Enabled {
|
||||
continue
|
||||
}
|
||||
|
||||
var allowedips []net.IPNet
|
||||
var peer wgtypes.PeerConfig
|
||||
if forIngressNode && extPeer.Address != "" {
|
||||
if extPeer.Address != "" {
|
||||
var peeraddr = net.IPNet{
|
||||
IP: net.ParseIP(extPeer.Address),
|
||||
Mask: net.CIDRMask(32, 32),
|
||||
@@ -756,7 +791,7 @@ func getExtPeers(node *models.Node, forIngressNode bool) ([]wgtypes.PeerConfig,
|
||||
}
|
||||
}
|
||||
|
||||
if forIngressNode && extPeer.Address6 != "" {
|
||||
if extPeer.Address6 != "" {
|
||||
var addr6 = net.IPNet{
|
||||
IP: net.ParseIP(extPeer.Address6),
|
||||
Mask: net.CIDRMask(128, 128),
|
||||
@@ -765,26 +800,6 @@ func getExtPeers(node *models.Node, forIngressNode bool) ([]wgtypes.PeerConfig,
|
||||
allowedips = append(allowedips, addr6)
|
||||
}
|
||||
}
|
||||
if !forIngressNode {
|
||||
if extPeer.InternalIPAddr != "" {
|
||||
peerInternalAddr := net.IPNet{
|
||||
IP: net.ParseIP(extPeer.InternalIPAddr),
|
||||
Mask: net.CIDRMask(32, 32),
|
||||
}
|
||||
if peerInternalAddr.IP != nil && peerInternalAddr.Mask != nil {
|
||||
allowedips = append(allowedips, peerInternalAddr)
|
||||
}
|
||||
}
|
||||
if extPeer.InternalIPAddr6 != "" {
|
||||
peerInternalAddr6 := net.IPNet{
|
||||
IP: net.ParseIP(extPeer.InternalIPAddr6),
|
||||
Mask: net.CIDRMask(32, 32),
|
||||
}
|
||||
if peerInternalAddr6.IP != nil && peerInternalAddr6.Mask != nil {
|
||||
allowedips = append(allowedips, peerInternalAddr6)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
primaryAddr := extPeer.Address
|
||||
if primaryAddr == "" {
|
||||
@@ -806,7 +821,7 @@ func getExtPeers(node *models.Node, forIngressNode bool) ([]wgtypes.PeerConfig,
|
||||
|
||||
}
|
||||
|
||||
func getExtPeersForProxy(node *models.Node, proxyPeerConf map[string]proxy_models.PeerConf) ([]wgtypes.PeerConfig, map[string]proxy_models.PeerConf, error) {
|
||||
func getExtPeersForProxy(node *models.Node, proxyPeerConf map[string]models.PeerConf) ([]wgtypes.PeerConfig, map[string]models.PeerConf, error) {
|
||||
var peers []wgtypes.PeerConfig
|
||||
host, err := GetHost(node.HostID.String())
|
||||
if err != nil {
|
||||
@@ -824,7 +839,8 @@ func getExtPeersForProxy(node *models.Node, proxyPeerConf map[string]proxy_model
|
||||
continue
|
||||
}
|
||||
|
||||
if host.PublicKey.String() == extPeer.PublicKey {
|
||||
if host.PublicKey.String() == extPeer.PublicKey ||
|
||||
extPeer.IngressGatewayID != node.ID.String() || !extPeer.Enabled {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -855,14 +871,9 @@ func getExtPeersForProxy(node *models.Node, proxyPeerConf map[string]proxy_model
|
||||
ReplaceAllowedIPs: true,
|
||||
AllowedIPs: allowedips,
|
||||
}
|
||||
extInternalPrimaryAddr := extPeer.InternalIPAddr
|
||||
if extInternalPrimaryAddr == "" {
|
||||
extInternalPrimaryAddr = extPeer.InternalIPAddr6
|
||||
}
|
||||
extConf := proxy_models.PeerConf{
|
||||
extConf := models.PeerConf{
|
||||
IsExtClient: true,
|
||||
Address: net.ParseIP(extPeer.Address),
|
||||
ExtInternalIp: net.ParseIP(extInternalPrimaryAddr),
|
||||
}
|
||||
proxyPeerConf[peer.PublicKey.String()] = extConf
|
||||
|
||||
@@ -879,7 +890,7 @@ func GetAllowedIPs(node, peer *models.Node, metrics *models.Metrics) []net.IPNet
|
||||
|
||||
// handle ingress gateway peers
|
||||
if peer.IsIngressGateway {
|
||||
extPeers, _, err := getExtPeers(peer, false)
|
||||
extPeers, _, err := getExtPeers(peer)
|
||||
if err != nil {
|
||||
logger.Log(2, "could not retrieve ext peers for ", peer.ID.String(), err.Error())
|
||||
}
|
||||
@@ -1057,7 +1068,7 @@ func GetPeerUpdateForRelayedNode(node *models.Node, udppeers map[string]string)
|
||||
peers = append(peers, peerData)
|
||||
//if ingress add extclients
|
||||
if node.IsIngressGateway {
|
||||
extPeers, _, err := getExtPeers(node, true)
|
||||
extPeers, _, err := getExtPeers(node)
|
||||
if err == nil {
|
||||
peers = append(peers, extPeers...)
|
||||
} else {
|
||||
@@ -1140,3 +1151,15 @@ func getNodeAllowedIPs(peer, node *models.Node) []net.IPNet {
|
||||
}
|
||||
return allowedips
|
||||
}
|
||||
|
||||
func getCIDRMaskFromAddr(addr string) net.IPMask {
|
||||
cidr := net.CIDRMask(32, 32)
|
||||
ipAddr, err := netip.ParseAddr(addr)
|
||||
if err != nil {
|
||||
return cidr
|
||||
}
|
||||
if ipAddr.Is6() {
|
||||
cidr = net.CIDRMask(128, 128)
|
||||
}
|
||||
return cidr
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package pro
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/models/promodels"
|
||||
@@ -18,8 +19,13 @@ func TestNetworkUserLogic(t *testing.T) {
|
||||
NetID: "skynet",
|
||||
AddressRange: "192.168.0.0/24",
|
||||
}
|
||||
nodes := []models.LegacyNode{
|
||||
models.LegacyNode{ID: "coolnode"},
|
||||
tmpCNode := models.CommonNode{
|
||||
ID: uuid.New(),
|
||||
}
|
||||
tempNode := models.Node{}
|
||||
tempNode.CommonNode = tmpCNode
|
||||
nodes := []models.Node{
|
||||
tempNode,
|
||||
}
|
||||
|
||||
clients := []models.ExtClient{
|
||||
@@ -63,10 +69,10 @@ func TestNetworkUserLogic(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Successful net user node isallowed", func(t *testing.T) {
|
||||
networkUser.Nodes = append(networkUser.Nodes, "coolnode")
|
||||
networkUser.Nodes = append(networkUser.Nodes, nodes[0].ID.String())
|
||||
err := UpdateNetworkUser(network.NetID, &networkUser)
|
||||
assert.Nil(t, err)
|
||||
isUserNodeAllowed := IsUserNodeAllowed(nodes[:], network.NetID, string(networkUser.ID), "coolnode")
|
||||
isUserNodeAllowed := IsUserNodeAllowed(nodes[:], network.NetID, string(networkUser.ID), nodes[0].ID.String())
|
||||
assert.True(t, isUserNodeAllowed)
|
||||
})
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
)
|
||||
@@ -33,9 +31,3 @@ func EnterpriseCheck() {
|
||||
check()
|
||||
}
|
||||
}
|
||||
|
||||
// == Private ==
|
||||
|
||||
func isDeleteError(err error) bool {
|
||||
return err != nil && strings.Contains(err.Error(), models.NODE_DELETE)
|
||||
}
|
||||
|
||||
@@ -19,9 +19,6 @@ var (
|
||||
Free_Tier = false
|
||||
)
|
||||
|
||||
// constant for database key for storing server ids
|
||||
const server_id_key = "nm-server-id"
|
||||
|
||||
type serverData struct {
|
||||
PrivateKey string `json:"privatekey,omitempty" bson:"privatekey,omitempty"`
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
crand "crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"net"
|
||||
@@ -15,8 +14,6 @@ import (
|
||||
|
||||
"github.com/c-robinson/iplib"
|
||||
"github.com/gravitl/netmaker/database"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/netclient/ncutils"
|
||||
)
|
||||
|
||||
// IsBase64 - checks if a string is in base64 format
|
||||
@@ -42,26 +39,12 @@ func FileExists(f string) bool {
|
||||
}
|
||||
|
||||
// IsAddressInCIDR - util to see if an address is in a cidr or not
|
||||
func IsAddressInCIDR(address, cidr string) bool {
|
||||
func IsAddressInCIDR(address net.IP, cidr string) bool {
|
||||
var _, currentCIDR, cidrErr = net.ParseCIDR(cidr)
|
||||
if cidrErr != nil {
|
||||
return false
|
||||
}
|
||||
var addrParts = strings.Split(address, ".")
|
||||
var addrPartLength = len(addrParts)
|
||||
if addrPartLength != 4 {
|
||||
return false
|
||||
} else {
|
||||
if addrParts[addrPartLength-1] == "0" ||
|
||||
addrParts[addrPartLength-1] == "255" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
ip, _, err := net.ParseCIDR(fmt.Sprintf("%s/32", address))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return currentCIDR.Contains(ip)
|
||||
return currentCIDR.Contains(address)
|
||||
}
|
||||
|
||||
// SetNetworkNodesLastModified - sets the network nodes last modified
|
||||
@@ -113,26 +96,6 @@ func RandomString(length int) string {
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// == Private Methods ==
|
||||
|
||||
func setIPForwardingLinux() error {
|
||||
out, err := ncutils.RunCmd("sysctl net.ipv4.ip_forward", true)
|
||||
if err != nil {
|
||||
logger.Log(0, "WARNING: Error encountered setting ip forwarding. This can break functionality.")
|
||||
return err
|
||||
} else {
|
||||
s := strings.Fields(string(out))
|
||||
if s[2] != "1" {
|
||||
_, err = ncutils.RunCmd("sysctl -w net.ipv4.ip_forward=1", true)
|
||||
if err != nil {
|
||||
logger.Log(0, "WARNING: Error encountered setting ip forwarding. You may want to investigate this.")
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// StringSliceContains - sees if a string slice contains a string element
|
||||
func StringSliceContains(slice []string, item string) bool {
|
||||
for _, s := range slice {
|
||||
@@ -143,8 +106,6 @@ func StringSliceContains(slice []string, item string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// == private ==
|
||||
|
||||
// NormalCIDR - returns the first address of CIDR
|
||||
func NormalizeCIDR(address string) (string, error) {
|
||||
ip, IPNet, err := net.ParseCIDR(address)
|
||||
@@ -161,23 +122,6 @@ func NormalizeCIDR(address string) (string, error) {
|
||||
return IPNet.String(), nil
|
||||
}
|
||||
|
||||
func getNetworkProtocols(cidrs []string) (bool, bool) {
|
||||
ipv4 := false
|
||||
ipv6 := false
|
||||
for _, cidr := range cidrs {
|
||||
ip, _, err := net.ParseCIDR(cidr)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if ip.To4() == nil {
|
||||
ipv6 = true
|
||||
} else {
|
||||
ipv4 = true
|
||||
}
|
||||
}
|
||||
return ipv4, ipv6
|
||||
}
|
||||
|
||||
// StringDifference - returns the elements in `a` that aren't in `b`.
|
||||
func StringDifference(a, b []string) []string {
|
||||
mb := make(map[string]struct{}, len(b))
|
||||
@@ -206,3 +150,5 @@ func CheckIfFileExists(filePath string) bool {
|
||||
func RemoveStringSlice(slice []string, i int) []string {
|
||||
return append(slice[:i], slice[i+1:]...)
|
||||
}
|
||||
|
||||
// == private ==
|
||||
|
||||
@@ -25,6 +25,7 @@ var (
|
||||
|
||||
// CheckZombies - checks if new node has same macaddress as existing node
|
||||
// if so, existing node is added to zombie node quarantine list
|
||||
// also cleans up nodes past their expiration date
|
||||
func CheckZombies(newnode *models.Node, mac net.HardwareAddr) {
|
||||
nodes, err := GetNetworkNodes(newnode.Network)
|
||||
if err != nil {
|
||||
@@ -32,12 +33,11 @@ func CheckZombies(newnode *models.Node, mac net.HardwareAddr) {
|
||||
return
|
||||
}
|
||||
for _, node := range nodes {
|
||||
host, err := GetHost(node.HostID.String())
|
||||
if err != nil {
|
||||
// should we delete the node if host not found ??
|
||||
if node.ID == newnode.ID {
|
||||
//skip self
|
||||
continue
|
||||
}
|
||||
if host.MacAddress.String() == mac.String() {
|
||||
if node.HostID == newnode.HostID || time.Now().After(node.ExpirationDateTime) {
|
||||
logger.Log(0, "adding ", node.ID.String(), " to zombie list")
|
||||
newZombie <- node.ID
|
||||
}
|
||||
@@ -45,7 +45,7 @@ func CheckZombies(newnode *models.Node, mac net.HardwareAddr) {
|
||||
}
|
||||
|
||||
// ManageZombies - goroutine which adds/removes/deletes nodes from the zombie node quarantine list
|
||||
func ManageZombies(ctx context.Context) {
|
||||
func ManageZombies(ctx context.Context, peerUpdate chan *models.Node) {
|
||||
logger.Log(2, "Zombie management started")
|
||||
InitializeZombies()
|
||||
for {
|
||||
@@ -80,11 +80,13 @@ func ManageZombies(ctx context.Context) {
|
||||
zombies = append(zombies[:i], zombies[i+1:]...)
|
||||
continue
|
||||
}
|
||||
if time.Since(node.LastCheckIn) > time.Minute*ZOMBIE_DELETE_TIME {
|
||||
if time.Since(node.LastCheckIn) > time.Minute*ZOMBIE_DELETE_TIME || time.Now().After(node.ExpirationDateTime) {
|
||||
if err := DeleteNode(&node, true); err != nil {
|
||||
logger.Log(1, "error deleting zombie node", zombies[i].String(), err.Error())
|
||||
continue
|
||||
}
|
||||
node.Action = models.NODE_DELETE
|
||||
peerUpdate <- &node
|
||||
logger.Log(1, "deleting zombie node", node.ID.String())
|
||||
zombies = append(zombies[:i], zombies[i+1:]...)
|
||||
}
|
||||
|
||||
16
main.go
16
main.go
@@ -110,12 +110,6 @@ func initialize() { // Client Mode Prereq Check
|
||||
logger.FatalLog("To run in client mode requires root privileges. Either disable client mode or run with sudo.")
|
||||
}
|
||||
}
|
||||
// initialize iptables to ensure gateways work correctly and mq is forwarded if containerized
|
||||
if servercfg.ManageIPTables() != "off" {
|
||||
if err = serverctl.InitIPTables(true); err != nil {
|
||||
logger.FatalLog("Unable to initialize iptables on host:", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if servercfg.IsDNSMode() {
|
||||
err := functions.SetDNSDir()
|
||||
@@ -191,7 +185,15 @@ func runMessageQueue(wg *sync.WaitGroup) {
|
||||
mq.SetupMQTT()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go mq.Keepalive(ctx)
|
||||
go logic.ManageZombies(ctx)
|
||||
go func() {
|
||||
peerUpdate := make(chan *models.Node)
|
||||
go logic.ManageZombies(ctx, peerUpdate)
|
||||
for nodeUpdate := range peerUpdate {
|
||||
if err := mq.NodeUpdate(nodeUpdate); err != nil {
|
||||
logger.Log(0, "failed to send peer update for deleted node: ", nodeUpdate.ID.String(), err.Error())
|
||||
}
|
||||
}
|
||||
}()
|
||||
go logic.PurgePendingNodes(ctx)
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, syscall.SIGTERM, os.Interrupt)
|
||||
|
||||
111
metrics/metrics.go
Normal file
111
metrics/metrics.go
Normal 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
|
||||
}
|
||||
@@ -10,5 +10,4 @@ type AccessToken struct {
|
||||
type ClientConfig struct {
|
||||
Network string `json:"network"`
|
||||
Key string `json:"key"`
|
||||
LocalRange string `json:"localrange"`
|
||||
}
|
||||
|
||||
@@ -13,9 +13,9 @@ type ApiHost struct {
|
||||
Debug bool `json:"debug"`
|
||||
IsStatic bool `json:"isstatic"`
|
||||
ListenPort int `json:"listenport"`
|
||||
LocalRange string `json:"localrange"`
|
||||
LocalListenPort int `json:"locallistenport"`
|
||||
ProxyListenPort int `json:"proxy_listen_port"`
|
||||
PublicListenPort int `json:"public_listen_port" yaml:"public_listen_port"`
|
||||
MTU int `json:"mtu" yaml:"mtu"`
|
||||
Interfaces []Iface `json:"interfaces" yaml:"interfaces"`
|
||||
DefaultInterface string `json:"defaultinterface" yaml:"defautlinterface"`
|
||||
@@ -50,16 +50,13 @@ func (h *Host) ConvertNMHostToAPI() *ApiHost {
|
||||
}
|
||||
a.IsStatic = h.IsStatic
|
||||
a.ListenPort = h.ListenPort
|
||||
a.LocalRange = h.LocalRange.String()
|
||||
if isEmptyAddr(a.LocalRange) {
|
||||
a.LocalRange = ""
|
||||
}
|
||||
a.MTU = h.MTU
|
||||
a.MacAddress = h.MacAddress.String()
|
||||
a.Name = h.Name
|
||||
a.OS = h.OS
|
||||
a.Nodes = h.Nodes
|
||||
a.ProxyEnabled = h.ProxyEnabled
|
||||
a.PublicListenPort = h.PublicListenPort
|
||||
a.ProxyListenPort = h.ProxyListenPort
|
||||
a.PublicKey = h.PublicKey.String()
|
||||
a.Verbosity = h.Verbosity
|
||||
@@ -106,14 +103,6 @@ func (a *ApiHost) ConvertAPIHostToNMHost(currentHost *Host) *Host {
|
||||
h.RelayedHosts = a.RelayedHosts
|
||||
h.IsRelay = a.IsRelay
|
||||
h.IsRelayed = a.IsRelayed
|
||||
if len(a.LocalRange) > 0 {
|
||||
_, localRange, err := net.ParseCIDR(a.LocalRange)
|
||||
if err == nil {
|
||||
h.LocalRange = *localRange
|
||||
}
|
||||
} else if !isEmptyAddr(currentHost.LocalRange.String()) {
|
||||
h.LocalRange = currentHost.LocalRange
|
||||
}
|
||||
h.ProxyEnabled = a.ProxyEnabled
|
||||
h.IsDefault = a.IsDefault
|
||||
|
||||
|
||||
@@ -14,8 +14,6 @@ type ApiNode struct {
|
||||
Address string `json:"address" validate:"omitempty,ipv4"`
|
||||
Address6 string `json:"address6" validate:"omitempty,ipv6"`
|
||||
LocalAddress string `json:"localaddress" validate:"omitempty,ipv4"`
|
||||
PostUp string `json:"postup"`
|
||||
PostDown string `json:"postdown"`
|
||||
AllowedIPs []string `json:"allowedips"`
|
||||
PersistentKeepalive int32 `json:"persistentkeepalive"`
|
||||
LastModified int64 `json:"lastmodified"`
|
||||
@@ -53,8 +51,6 @@ func (a *ApiNode) ConvertToServerNode(currentNode *Node) *Node {
|
||||
convertedNode.Connected = a.Connected
|
||||
convertedNode.ID, _ = uuid.Parse(a.ID)
|
||||
convertedNode.HostID, _ = uuid.Parse(a.HostID)
|
||||
convertedNode.PostUp = a.PostUp
|
||||
convertedNode.PostDown = a.PostDown
|
||||
convertedNode.IsLocal = a.IsLocal
|
||||
convertedNode.IsRelay = a.IsRelay
|
||||
convertedNode.IsRelayed = a.IsRelayed
|
||||
@@ -99,8 +95,8 @@ func (a *ApiNode) ConvertToServerNode(currentNode *Node) *Node {
|
||||
}
|
||||
ip6, addr6, err := net.ParseCIDR(a.Address6)
|
||||
if err == nil {
|
||||
convertedNode.Address = *addr6
|
||||
convertedNode.Address.IP = ip6
|
||||
convertedNode.Address6 = *addr6
|
||||
convertedNode.Address6.IP = ip6
|
||||
}
|
||||
convertedNode.FailoverNode, _ = uuid.Parse(a.FailoverNode)
|
||||
convertedNode.LastModified = time.Unix(a.LastModified, 0)
|
||||
@@ -127,12 +123,11 @@ func (nm *Node) ConvertToAPINode() *ApiNode {
|
||||
if isEmptyAddr(apiNode.LocalAddress) {
|
||||
apiNode.LocalAddress = ""
|
||||
}
|
||||
apiNode.PostDown = nm.PostDown
|
||||
apiNode.PostUp = nm.PostUp
|
||||
apiNode.PersistentKeepalive = int32(nm.PersistentKeepalive.Seconds())
|
||||
apiNode.LastModified = nm.LastModified.Unix()
|
||||
apiNode.LastCheckIn = nm.LastCheckIn.Unix()
|
||||
apiNode.LastPeerUpdate = nm.LastPeerUpdate.Unix()
|
||||
apiNode.ExpirationDateTime = nm.ExpirationDateTime.Unix()
|
||||
apiNode.Network = nm.Network
|
||||
apiNode.NetworkRange = nm.NetworkRange.String()
|
||||
if isEmptyAddr(apiNode.NetworkRange) {
|
||||
|
||||
@@ -14,6 +14,4 @@ type ExtClient struct {
|
||||
LastModified int64 `json:"lastmodified" bson:"lastmodified"`
|
||||
Enabled bool `json:"enabled" bson:"enabled"`
|
||||
OwnerID string `json:"ownerid" bson:"ownerid"`
|
||||
InternalIPAddr string `json:"internal_ip_addr" bson:"internal_ip_addr"`
|
||||
InternalIPAddr6 string `json:"internal_ip_addr6" bson:"internal_ip_addr6"`
|
||||
}
|
||||
|
||||
@@ -24,8 +24,6 @@ type Host struct {
|
||||
Interface string `json:"interface" yaml:"interface"`
|
||||
Debug bool `json:"debug" yaml:"debug"`
|
||||
ListenPort int `json:"listenport" yaml:"listenport"`
|
||||
LocalAddress net.IPNet `json:"localaddress" yaml:"localaddress"`
|
||||
LocalRange net.IPNet `json:"localrange" yaml:"localrange"`
|
||||
PublicListenPort int `json:"public_listen_port" yaml:"public_listen_port"`
|
||||
ProxyListenPort int `json:"proxy_listen_port" yaml:"proxy_listen_port"`
|
||||
MTU int `json:"mtu" yaml:"mtu"`
|
||||
|
||||
8
models/migrate.go
Normal file
8
models/migrate.go
Normal 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
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
proxy_models "github.com/gravitl/netclient/nmproxy/models"
|
||||
"net"
|
||||
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
|
||||
@@ -13,18 +14,41 @@ type PeerUpdate struct {
|
||||
Peers []wgtypes.PeerConfig `json:"peers" bson:"peers" yaml:"peers"`
|
||||
DNS string `json:"dns" bson:"dns" yaml:"dns"`
|
||||
PeerIDs PeerMap `json:"peerids" bson:"peerids" yaml:"peerids"`
|
||||
ProxyUpdate proxy_models.ProxyManagerPayload `json:"proxy_update" bson:"proxy_update" yaml:"proxy_update"`
|
||||
ProxyUpdate ProxyManagerPayload `json:"proxy_update" bson:"proxy_update" yaml:"proxy_update"`
|
||||
}
|
||||
|
||||
// HostPeerUpdate - struct for host peer updates
|
||||
type HostPeerUpdate struct {
|
||||
Host Host `json:"host" bson:"host" yaml:"host"`
|
||||
Server string `json:"server" bson:"server" yaml:"server"`
|
||||
ServerVersion string `json:"serverversion" bson:"serverversion" yaml:"serverversion"`
|
||||
ServerAddrs []ServerAddr `json:"serveraddrs" bson:"serveraddrs" yaml:"serveraddrs"`
|
||||
Network map[string]NetworkInfo `json:"network" bson:"network" yaml:"network"`
|
||||
Peers []wgtypes.PeerConfig `json:"peers" bson:"peers" yaml:"peers"`
|
||||
PeerIDs HostPeerMap `json:"peerids" bson:"peerids" yaml:"peerids"`
|
||||
ProxyUpdate 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
|
||||
|
||||
@@ -17,7 +17,6 @@ type Network struct {
|
||||
DefaultInterface string `json:"defaultinterface" bson:"defaultinterface" validate:"min=1,max=15"`
|
||||
DefaultListenPort int32 `json:"defaultlistenport,omitempty" bson:"defaultlistenport,omitempty" validate:"omitempty,min=1024,max=65535"`
|
||||
NodeLimit int32 `json:"nodelimit" bson:"nodelimit"`
|
||||
DefaultPostUp string `json:"defaultpostup" bson:"defaultpostup"`
|
||||
DefaultPostDown string `json:"defaultpostdown" bson:"defaultpostdown"`
|
||||
DefaultKeepalive int32 `json:"defaultkeepalive" bson:"defaultkeepalive" validate:"omitempty,max=1000"`
|
||||
AccessKeys []AccessKey `json:"accesskeys" bson:"accesskeys"`
|
||||
@@ -25,8 +24,6 @@ type Network struct {
|
||||
IsLocal string `json:"islocal" bson:"islocal" validate:"checkyesorno"`
|
||||
IsIPv4 string `json:"isipv4" bson:"isipv4" validate:"checkyesorno"`
|
||||
IsIPv6 string `json:"isipv6" bson:"isipv6" validate:"checkyesorno"`
|
||||
IsPointToSite string `json:"ispointtosite" bson:"ispointtosite" validate:"checkyesorno"`
|
||||
LocalRange string `json:"localrange" bson:"localrange" validate:"omitempty,cidr"`
|
||||
DefaultUDPHolePunch string `json:"defaultudpholepunch" bson:"defaultudpholepunch" validate:"checkyesorno"`
|
||||
DefaultExtClientDNS string `json:"defaultextclientdns" bson:"defaultextclientdns"`
|
||||
DefaultMTU int32 `json:"defaultmtu" bson:"defaultmtu"`
|
||||
@@ -57,9 +54,6 @@ func (network *Network) SetDefaults() {
|
||||
if network.IsLocal == "" {
|
||||
network.IsLocal = "no"
|
||||
}
|
||||
if network.IsPointToSite == "" {
|
||||
network.IsPointToSite = "no"
|
||||
}
|
||||
if network.DefaultInterface == "" {
|
||||
if len(network.NetID) < 13 {
|
||||
network.DefaultInterface = "nm-" + network.NetID
|
||||
|
||||
@@ -13,13 +13,4 @@ package models
|
||||
// assert.Equal(t, "NetID is not editable", err.Error())
|
||||
// t.Log(err, Range, local)
|
||||
// })
|
||||
// t.Run("LocalRange", func(t *testing.T) {
|
||||
// var networkupdate models.Network
|
||||
// //NetID needs to be set as it will be in updateNetwork
|
||||
// networkupdate.NetID = "skynet"
|
||||
// networkupdate.LocalRange = "192.168.0.1/24"
|
||||
// Range, local, err := network.Update(&networkupdate)
|
||||
// assert.Nil(t, err)
|
||||
// t.Log(err, Range, local)
|
||||
// })
|
||||
//}
|
||||
|
||||
@@ -15,7 +15,7 @@ const (
|
||||
// NODE_SERVER_NAME - the default server name
|
||||
NODE_SERVER_NAME = "netmaker"
|
||||
// TEN_YEARS_IN_SECONDS - ten years in seconds
|
||||
TEN_YEARS_IN_SECONDS = 300000000
|
||||
TEN_YEARS_IN_SECONDS = 315670000000000000
|
||||
// MAX_NAME_LENGTH - max name length of node
|
||||
MAX_NAME_LENGTH = 62
|
||||
// == ACTIONS == (can only be set by server)
|
||||
@@ -66,8 +66,6 @@ type CommonNode struct {
|
||||
Connected bool `json:"connected" yaml:"connected"`
|
||||
Address net.IPNet `json:"address" yaml:"address"`
|
||||
Address6 net.IPNet `json:"address6" yaml:"address6"`
|
||||
PostUp string `json:"postup" yaml:"postup"`
|
||||
PostDown string `json:"postdown" yaml:"postdown"`
|
||||
Action string `json:"action" yaml:"action"`
|
||||
LocalAddress net.IPNet `json:"localaddress" yaml:"localaddress"`
|
||||
IsLocal bool `json:"islocal" yaml:"islocal"`
|
||||
@@ -115,8 +113,6 @@ type LegacyNode struct {
|
||||
ProxyListenPort int32 `json:"proxy_listen_port" bson:"proxy_listen_port" yaml:"proxy_listen_port" validate:"numeric,min=0,max=65535"`
|
||||
PublicKey string `json:"publickey" bson:"publickey" yaml:"publickey" validate:"required,base64"`
|
||||
Endpoint string `json:"endpoint" bson:"endpoint" yaml:"endpoint" validate:"required,ip"`
|
||||
PostUp string `json:"postup" bson:"postup" yaml:"postup"`
|
||||
PostDown string `json:"postdown" bson:"postdown" yaml:"postdown"`
|
||||
AllowedIPs []string `json:"allowedips" bson:"allowedips" yaml:"allowedips"`
|
||||
PersistentKeepalive int32 `json:"persistentkeepalive" bson:"persistentkeepalive" yaml:"persistentkeepalive" validate:"omitempty,numeric,max=1000"`
|
||||
IsHub string `json:"ishub" bson:"ishub" yaml:"ishub" validate:"checkyesorno"`
|
||||
@@ -150,7 +146,6 @@ type LegacyNode struct {
|
||||
IsServer string `json:"isserver" bson:"isserver" yaml:"isserver" validate:"checkyesorno"`
|
||||
Action string `json:"action" bson:"action" yaml:"action"`
|
||||
IsLocal string `json:"islocal" bson:"islocal" yaml:"islocal" validate:"checkyesorno"`
|
||||
LocalRange string `json:"localrange" bson:"localrange" yaml:"localrange"`
|
||||
IPForwarding string `json:"ipforwarding" bson:"ipforwarding" yaml:"ipforwarding" validate:"checkyesorno"`
|
||||
OS string `json:"os" bson:"os" yaml:"os"`
|
||||
MTU int32 `json:"mtu" bson:"mtu" yaml:"mtu"`
|
||||
@@ -197,13 +192,8 @@ func (node *Node) PrimaryAddress() string {
|
||||
}
|
||||
|
||||
// Node.SetDefaultConnected
|
||||
func (node *LegacyNode) SetDefaultConnected() {
|
||||
if node.Connected == "" {
|
||||
node.Connected = "yes"
|
||||
}
|
||||
if node.IsServer == "yes" {
|
||||
node.Connected = "yes"
|
||||
}
|
||||
func (node *Node) SetDefaultConnected() {
|
||||
node.Connected = true
|
||||
}
|
||||
|
||||
// Node.SetDefaultACL
|
||||
@@ -374,12 +364,6 @@ func (newNode *Node) Fill(currentNode *Node) { // TODO add new field for nftable
|
||||
if newNode.Address6.String() == "" {
|
||||
newNode.Address6 = currentNode.Address6
|
||||
}
|
||||
if newNode.PostUp == "" {
|
||||
newNode.PostUp = currentNode.PostUp
|
||||
}
|
||||
if newNode.PostDown == "" {
|
||||
newNode.PostDown = currentNode.PostDown
|
||||
}
|
||||
if newNode.PersistentKeepalive < 0 {
|
||||
newNode.PersistentKeepalive = currentNode.PersistentKeepalive
|
||||
}
|
||||
@@ -495,13 +479,6 @@ func (ln *LegacyNode) ConvertToNewNode() (*Host, *Node) {
|
||||
host.HostPass = ln.Password
|
||||
host.Name = ln.Name
|
||||
host.ListenPort = int(ln.ListenPort)
|
||||
if _, cidr, err := net.ParseCIDR(ln.LocalAddress); err == nil {
|
||||
host.LocalRange = *cidr
|
||||
} else {
|
||||
if _, cidr, err := net.ParseCIDR(ln.LocalRange); err == nil {
|
||||
host.LocalRange = *cidr
|
||||
}
|
||||
}
|
||||
host.ProxyListenPort = int(ln.ProxyListenPort)
|
||||
host.MTU = int(ln.MTU)
|
||||
host.PublicKey, _ = wgtypes.ParseKey(ln.PublicKey)
|
||||
@@ -540,8 +517,6 @@ func (ln *LegacyNode) ConvertToNewNode() (*Host, *Node) {
|
||||
Mask: net.CIDRMask(128, 128),
|
||||
}
|
||||
}
|
||||
node.PostUp = ln.PostUp
|
||||
node.PostDown = ln.PostDown
|
||||
node.Action = ln.Action
|
||||
node.IsLocal = parseBool(ln.IsLocal)
|
||||
node.IsEgressGateway = parseBool(ln.IsEgressGateway)
|
||||
@@ -565,8 +540,6 @@ func (n *Node) Legacy(h *Host, s *ServerConfig, net *Network) *LegacyNode {
|
||||
l.ProxyListenPort = int32(h.ProxyListenPort)
|
||||
l.PublicKey = h.PublicKey.String()
|
||||
l.Endpoint = h.EndpointIP.String()
|
||||
l.PostUp = n.PostUp
|
||||
l.PostDown = n.PostDown
|
||||
//l.AllowedIPs =
|
||||
l.AccessKey = ""
|
||||
l.Interface = WIREGUARD_INTERFACE
|
||||
@@ -594,7 +567,6 @@ func (n *Node) Legacy(h *Host, s *ServerConfig, net *Network) *LegacyNode {
|
||||
l.DNSOn = formatBool(n.DNSOn)
|
||||
l.Action = n.Action
|
||||
l.IsLocal = formatBool(n.IsLocal)
|
||||
l.LocalRange = h.LocalRange.String()
|
||||
l.IPForwarding = formatBool(h.IPForwarding)
|
||||
l.OS = h.OS
|
||||
l.MTU = int32(h.MTU)
|
||||
|
||||
68
models/proxy.go
Normal file
68
models/proxy.go
Normal 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
|
||||
}
|
||||
@@ -161,8 +161,6 @@ type EgressGatewayRequest struct {
|
||||
NatEnabled string `json:"natenabled" bson:"natenabled"`
|
||||
Ranges []string `json:"ranges" bson:"ranges"`
|
||||
Interface string `json:"interface" bson:"interface"`
|
||||
PostUp string `json:"postup" bson:"postup"`
|
||||
PostDown string `json:"postdown" bson:"postdown"`
|
||||
}
|
||||
|
||||
// RelayRequest - relay request struct
|
||||
|
||||
@@ -29,14 +29,14 @@ func Ping(client mqtt.Client, msg mqtt.Message) {
|
||||
}
|
||||
node, err := logic.GetNodeByID(id)
|
||||
if err != nil {
|
||||
logger.Log(0, "mq-ping error getting node: ", err.Error())
|
||||
logger.Log(3, "mq-ping error getting node: ", err.Error())
|
||||
record, err := database.FetchRecord(database.NODES_TABLE_NAME, id)
|
||||
if err != nil {
|
||||
logger.Log(0, "error reading database ", err.Error())
|
||||
logger.Log(3, "error reading database ", err.Error())
|
||||
return
|
||||
}
|
||||
logger.Log(0, "record from database")
|
||||
logger.Log(0, record)
|
||||
logger.Log(3, "record from database")
|
||||
logger.Log(3, record)
|
||||
return
|
||||
}
|
||||
decrypted, decryptErr := decryptMsg(&node, msg.Payload())
|
||||
@@ -141,11 +141,11 @@ func UpdateHost(client mqtt.Client, msg mqtt.Message) {
|
||||
logger.Log(1, "error unmarshaling payload ", err.Error())
|
||||
return
|
||||
}
|
||||
logger.Log(0, "recieved host update for host: ", id)
|
||||
logger.Log(3, fmt.Sprintf("recieved host update: %s\n", hostUpdate.Host.ID.String()))
|
||||
var sendPeerUpdate bool
|
||||
switch hostUpdate.Action {
|
||||
case models.UpdateHost:
|
||||
sendPeerUpdate = updateHostFromClient(&hostUpdate.Host, currentHost)
|
||||
sendPeerUpdate = logic.UpdateHostFromClient(&hostUpdate.Host, currentHost)
|
||||
err := logic.UpsertHost(currentHost)
|
||||
if err != nil {
|
||||
logger.Log(0, "failed to update host: ", currentHost.ID.String(), err.Error())
|
||||
@@ -168,6 +168,12 @@ func UpdateHost(client mqtt.Client, msg mqtt.Message) {
|
||||
logger.Log(0, "failed to pulish peer update: ", err.Error())
|
||||
}
|
||||
}
|
||||
if sendPeerUpdate {
|
||||
err := PublishPeerUpdate()
|
||||
if err != nil {
|
||||
logger.Log(0, "failed to pulish peer update: ", err.Error())
|
||||
}
|
||||
}
|
||||
// if servercfg.Is_EE && ifaceDelta {
|
||||
// if err = logic.EnterpriseResetAllPeersFailovers(currentHost.ID.String(), currentHost.Network); err != nil {
|
||||
// logger.Log(1, "failed to reset failover list during node update", currentHost.ID.String(), currentHost.Network)
|
||||
@@ -177,37 +183,6 @@ func UpdateHost(client mqtt.Client, msg mqtt.Message) {
|
||||
}(msg)
|
||||
}
|
||||
|
||||
// used for updating host on server with update recieved from client
|
||||
func updateHostFromClient(newHost, currHost *models.Host) (sendPeerUpdate bool) {
|
||||
|
||||
if newHost.ListenPort != 0 && currHost.ListenPort != newHost.ListenPort {
|
||||
currHost.ListenPort = newHost.ListenPort
|
||||
sendPeerUpdate = true
|
||||
}
|
||||
if newHost.ProxyListenPort != 0 && currHost.ProxyListenPort != newHost.ProxyListenPort {
|
||||
currHost.ProxyListenPort = newHost.ProxyListenPort
|
||||
sendPeerUpdate = true
|
||||
}
|
||||
if newHost.PublicListenPort != 0 && currHost.PublicListenPort != newHost.PublicListenPort {
|
||||
currHost.PublicListenPort = newHost.PublicListenPort
|
||||
sendPeerUpdate = true
|
||||
}
|
||||
if currHost.ProxyEnabled != newHost.ProxyEnabled {
|
||||
currHost.ProxyEnabled = newHost.ProxyEnabled
|
||||
sendPeerUpdate = true
|
||||
}
|
||||
if currHost.EndpointIP.String() != newHost.EndpointIP.String() {
|
||||
currHost.EndpointIP = newHost.EndpointIP
|
||||
sendPeerUpdate = true
|
||||
}
|
||||
currHost.DaemonInstalled = newHost.DaemonInstalled
|
||||
currHost.Debug = newHost.Debug
|
||||
currHost.Verbosity = newHost.Verbosity
|
||||
currHost.Version = newHost.Version
|
||||
currHost.Name = newHost.Name
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateMetrics message Handler -- handles updates from client nodes for metrics
|
||||
func UpdateMetrics(client mqtt.Client, msg mqtt.Message) {
|
||||
if servercfg.Is_EE {
|
||||
@@ -370,7 +345,7 @@ func updateNodeMetrics(currentNode *models.Node, newMetrics *models.Metrics) boo
|
||||
for _, node := range nodes {
|
||||
if !newMetrics.Connectivity[node.ID.String()].Connected &&
|
||||
len(newMetrics.Connectivity[node.ID.String()].NodeName) > 0 &&
|
||||
node.Connected == true &&
|
||||
node.Connected &&
|
||||
len(node.FailoverNode) > 0 &&
|
||||
!node.Failover {
|
||||
newMetrics.FailoverPeers[node.ID.String()] = node.FailoverNode.String()
|
||||
|
||||
@@ -6,12 +6,10 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
proxy_models "github.com/gravitl/netclient/nmproxy/models"
|
||||
"github.com/gravitl/netmaker/logger"
|
||||
"github.com/gravitl/netmaker/logic"
|
||||
"github.com/gravitl/netmaker/models"
|
||||
"github.com/gravitl/netmaker/servercfg"
|
||||
"github.com/gravitl/netmaker/serverctl"
|
||||
)
|
||||
|
||||
// PublishPeerUpdate --- determines and publishes a peer update to all the hosts
|
||||
@@ -26,6 +24,7 @@ func PublishPeerUpdate() error {
|
||||
return err
|
||||
}
|
||||
for _, host := range hosts {
|
||||
host := host
|
||||
err = PublishSingleHostUpdate(&host)
|
||||
if err != nil {
|
||||
logger.Log(1, "failed to publish peer update to host", host.ID.String(), ": ", err.Error())
|
||||
@@ -46,7 +45,7 @@ func PublishSingleHostUpdate(host *models.Host) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
proxyUpdate.Action = proxy_models.ProxyUpdate
|
||||
proxyUpdate.Action = models.ProxyUpdate
|
||||
peerUpdate.ProxyUpdate = proxyUpdate
|
||||
}
|
||||
|
||||
@@ -123,13 +122,7 @@ func sendPeers() {
|
||||
var force bool
|
||||
peer_force_send++
|
||||
if peer_force_send == 5 {
|
||||
|
||||
// run iptables update to ensure gateways work correctly and mq is forwarded if containerized
|
||||
if servercfg.ManageIPTables() != "off" {
|
||||
serverctl.InitIPTables(false)
|
||||
}
|
||||
servercfg.SetHost()
|
||||
|
||||
force = true
|
||||
peer_force_send = 0
|
||||
err := logic.TimerCheckpoint() // run telemetry & log dumps if 24 hours has passed..
|
||||
@@ -142,6 +135,7 @@ func sendPeers() {
|
||||
|
||||
for _, host := range hosts {
|
||||
if force {
|
||||
host := host
|
||||
logger.Log(2, "sending scheduled peer update (5 min)")
|
||||
err = PublishSingleHostUpdate(&host)
|
||||
if err != nil {
|
||||
|
||||
@@ -23,8 +23,6 @@ func IfaceDelta(currentNode *models.LegacyNode, newNode *models.LegacyNode) bool
|
||||
newNode.PersistentKeepalive != currentNode.PersistentKeepalive ||
|
||||
newNode.DNSOn != currentNode.DNSOn ||
|
||||
newNode.Connected != currentNode.Connected ||
|
||||
newNode.PostUp != currentNode.PostUp ||
|
||||
newNode.PostDown != currentNode.PostDown ||
|
||||
len(newNode.AllowedIPs) != len(currentNode.AllowedIPs) {
|
||||
return true
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
// }
|
||||
// }
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
509
scripts/nm-upgrade.sh
Normal 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 "-----------------------------------------------------------------"
|
||||
@@ -76,15 +76,7 @@ func GetServerConfig() config.ServerConfig {
|
||||
cfg.ClientID = authInfo[1]
|
||||
cfg.ClientSecret = authInfo[2]
|
||||
cfg.FrontendURL = GetFrontendURL()
|
||||
if GetRce() {
|
||||
cfg.RCE = "on"
|
||||
} else {
|
||||
cfg.RCE = "off"
|
||||
}
|
||||
cfg.Telemetry = Telemetry()
|
||||
cfg.ManageIPTables = ManageIPTables()
|
||||
services := strings.Join(GetPortForwardServiceList(), ",")
|
||||
cfg.PortForwardServices = services
|
||||
cfg.Server = GetServer()
|
||||
cfg.Verbosity = GetVerbosity()
|
||||
cfg.IsEE = "no"
|
||||
@@ -379,18 +371,6 @@ func Telemetry() string {
|
||||
return telemetry
|
||||
}
|
||||
|
||||
// ManageIPTables - checks if iptables should be manipulated on host
|
||||
func ManageIPTables() string {
|
||||
manage := "on"
|
||||
if os.Getenv("MANAGE_IPTABLES") == "off" {
|
||||
manage = "off"
|
||||
}
|
||||
if config.Config.Server.ManageIPTables == "off" {
|
||||
manage = "off"
|
||||
}
|
||||
return manage
|
||||
}
|
||||
|
||||
// GetServer - gets the server name
|
||||
func GetServer() string {
|
||||
server := ""
|
||||
@@ -528,19 +508,6 @@ func GetPlatform() string {
|
||||
return platform
|
||||
}
|
||||
|
||||
// GetIPForwardServiceList - get the list of services that the server should be forwarding
|
||||
func GetPortForwardServiceList() []string {
|
||||
//services := "mq,dns,ssh"
|
||||
services := ""
|
||||
if os.Getenv("PORT_FORWARD_SERVICES") != "" {
|
||||
services = os.Getenv("PORT_FORWARD_SERVICES")
|
||||
} else if config.Config.Server.PortForwardServices != "" {
|
||||
services = config.Config.Server.PortForwardServices
|
||||
}
|
||||
serviceSlice := strings.Split(services, ",")
|
||||
return serviceSlice
|
||||
}
|
||||
|
||||
// GetSQLConn - get the sql connection string
|
||||
func GetSQLConn() string {
|
||||
sqlconn := "http://"
|
||||
@@ -552,17 +519,6 @@ func GetSQLConn() string {
|
||||
return sqlconn
|
||||
}
|
||||
|
||||
// IsHostNetwork - checks if running on host network
|
||||
func IsHostNetwork() bool {
|
||||
ishost := false
|
||||
if os.Getenv("HOST_NETWORK") == "on" {
|
||||
ishost = true
|
||||
} else if config.Config.Server.HostNetwork == "on" {
|
||||
ishost = true
|
||||
}
|
||||
return ishost
|
||||
}
|
||||
|
||||
// GetNodeID - gets the node id
|
||||
func GetNodeID() string {
|
||||
var id string
|
||||
@@ -640,11 +596,6 @@ func GetAzureTenant() string {
|
||||
return azureTenant
|
||||
}
|
||||
|
||||
// GetRce - sees if Rce is enabled, off by default
|
||||
func GetRce() bool {
|
||||
return os.Getenv("RCE") == "on" || config.Config.Server.RCE == "on"
|
||||
}
|
||||
|
||||
// GetMQServerPort - get mq port for server
|
||||
func GetMQServerPort() string {
|
||||
port := "1883" //default
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -85,7 +85,7 @@ func setNetworkDefaults() error {
|
||||
}
|
||||
} else {
|
||||
network.SetDefaults()
|
||||
_, _, _, _, _, _, err = logic.UpdateNetwork(&network, &network)
|
||||
_, _, _, _, _, err = logic.UpdateNetwork(&network, &network)
|
||||
if err != nil {
|
||||
logger.Log(0, "could not set defaults on network", network.NetID)
|
||||
}
|
||||
|
||||
26
swagger.yaml
26
swagger.yaml
@@ -105,12 +105,6 @@ definitions:
|
||||
nodeid:
|
||||
type: string
|
||||
x-go-name: NodeID
|
||||
postdown:
|
||||
type: string
|
||||
x-go-name: PostDown
|
||||
postup:
|
||||
type: string
|
||||
x-go-name: PostUp
|
||||
ranges:
|
||||
items:
|
||||
type: string
|
||||
@@ -270,12 +264,6 @@ definitions:
|
||||
format: int32
|
||||
type: integer
|
||||
x-go-name: DefaultMTU
|
||||
defaultpostdown:
|
||||
type: string
|
||||
x-go-name: DefaultPostDown
|
||||
defaultpostup:
|
||||
type: string
|
||||
x-go-name: DefaultPostUp
|
||||
defaultudpholepunch:
|
||||
type: string
|
||||
x-go-name: DefaultUDPHolePunch
|
||||
@@ -291,9 +279,6 @@ definitions:
|
||||
ispointtosite:
|
||||
type: string
|
||||
x-go-name: IsPointToSite
|
||||
localrange:
|
||||
type: string
|
||||
x-go-name: LocalRange
|
||||
netid:
|
||||
type: string
|
||||
x-go-name: NetID
|
||||
@@ -432,9 +417,6 @@ definitions:
|
||||
format: int32
|
||||
type: integer
|
||||
x-go-name: LocalListenPort
|
||||
localrange:
|
||||
type: string
|
||||
x-go-name: LocalRange
|
||||
macaddress:
|
||||
type: string
|
||||
x-go-name: MacAddress
|
||||
@@ -460,12 +442,6 @@ definitions:
|
||||
format: int32
|
||||
type: integer
|
||||
x-go-name: PersistentKeepalive
|
||||
postdown:
|
||||
type: string
|
||||
x-go-name: PostDown
|
||||
postup:
|
||||
type: string
|
||||
x-go-name: PostUp
|
||||
publickey:
|
||||
type: string
|
||||
x-go-name: PublicKey
|
||||
@@ -644,8 +620,6 @@ definitions:
|
||||
type: string
|
||||
PublicIPService:
|
||||
type: string
|
||||
RCE:
|
||||
type: string
|
||||
RestBackend:
|
||||
type: string
|
||||
SQLConn:
|
||||
|
||||
@@ -467,17 +467,14 @@ func TestUpdateNetwork(t *testing.T) {
|
||||
})
|
||||
t.Run("UpdatePostUP", func(t *testing.T) {
|
||||
type Network struct {
|
||||
DefaultPostUp string
|
||||
}
|
||||
var network Network
|
||||
network.DefaultPostUp = "sudo wg add-conf wc-netmaker /etc/wireguard/peers/conf"
|
||||
response, err := api(t, network, http.MethodPut, baseURL+"/api/networks/skynet", "secretkey")
|
||||
assert.Nil(t, err, err)
|
||||
assert.Equal(t, http.StatusOK, response.StatusCode)
|
||||
defer response.Body.Close()
|
||||
err = json.NewDecoder(response.Body).Decode(&returnedNetwork)
|
||||
assert.Nil(t, err, err)
|
||||
assert.Equal(t, network.DefaultPostUp, returnedNetwork.DefaultPostUp)
|
||||
})
|
||||
t.Run("UpdatePostDown", func(t *testing.T) {
|
||||
type Network struct {
|
||||
|
||||
Reference in New Issue
Block a user