Browse Source

Merge branch 'develop' into bugfix_v0.14.7_nft

Matthew R. Kasun 3 years ago
parent
commit
43258b642e

+ 0 - 1
controllers/config/dnsconfig/netmaker.hosts

@@ -1 +0,0 @@
-10.0.0.2         testnode.skynet myhost.skynet

+ 1 - 0
controllers/controller.go

@@ -24,6 +24,7 @@ var HttpHandlers = []interface{}{
 	fileHandlers,
 	fileHandlers,
 	serverHandlers,
 	serverHandlers,
 	extClientHandlers,
 	extClientHandlers,
+	ipHandlers,
 }
 }
 
 
 // HandleRESTRequests - handles the rest requests
 // HandleRESTRequests - handles the rest requests

+ 72 - 0
controllers/ipservice.go

@@ -0,0 +1,72 @@
+package controller
+
+import (
+	"fmt"
+	"net"
+	"net/http"
+	"strings"
+
+	"github.com/gorilla/mux"
+)
+
+func ipHandlers(r *mux.Router) {
+	r.HandleFunc("/api/getip", http.HandlerFunc(getPublicIP)).Methods("GET")
+}
+
+func getPublicIP(w http.ResponseWriter, r *http.Request) {
+	r.Header.Set("Connection", "close")
+	ip, err := parseIP(r)
+	if err != nil {
+		w.WriteHeader(400)
+		if ip != "" {
+			w.Write([]byte("ip is invalid: " + ip))
+			return
+		} else {
+			w.Write([]byte("no ip found"))
+			return
+		}
+	} else {
+		if err != nil {
+			fmt.Println(err)
+		}
+	}
+	w.WriteHeader(200)
+	w.Write([]byte(ip))
+}
+
+func parseIP(r *http.Request) (string, error) {
+	// Get Public IP from header
+	ip := r.Header.Get("X-REAL-IP")
+	ipnet := net.ParseIP(ip)
+	if ipnet != nil && !ipIsPrivate(ipnet) {
+		return ip, nil
+	}
+
+	// If above fails, get Public IP from other header instead
+	forwardips := r.Header.Get("X-FORWARDED-FOR")
+	iplist := strings.Split(forwardips, ",")
+	for _, ip := range iplist {
+		ipnet := net.ParseIP(ip)
+		if ipnet != nil && !ipIsPrivate(ipnet) {
+			return ip, nil
+		}
+	}
+
+	// If above also fails, get Public IP from Remote Address of request
+	ip, _, err := net.SplitHostPort(r.RemoteAddr)
+	if err != nil {
+		return "", err
+	}
+	ipnet = net.ParseIP(ip)
+	if ipnet != nil {
+		if ipIsPrivate(ipnet) {
+			return ip, fmt.Errorf("ip is a private address")
+		}
+		return ip, nil
+	}
+	return "", fmt.Errorf("no ip found")
+}
+
+func ipIsPrivate(ipnet net.IP) bool {
+	return ipnet.IsPrivate() || ipnet.IsLoopback()
+}

+ 9 - 3
logic/peers.go

@@ -16,6 +16,7 @@ import (
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/servercfg"
 	"github.com/gravitl/netmaker/servercfg"
+	"golang.org/x/exp/slices"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 )
 
 
@@ -494,6 +495,11 @@ func GetPeerUpdateForRelayedNode(node *models.Node, udppeers map[string]string)
 }
 }
 
 
 func getEgressIPs(node, peer *models.Node) []net.IPNet {
 func getEgressIPs(node, peer *models.Node) []net.IPNet {
+	//check for internet gateway
+	internetGateway := false
+	if slices.Contains(peer.EgressGatewayRanges, "0.0.0.0/0") || slices.Contains(peer.EgressGatewayRanges, "::0") {
+		internetGateway = true
+	}
 	allowedips := []net.IPNet{}
 	allowedips := []net.IPNet{}
 	for _, iprange := range peer.EgressGatewayRanges { // go through each cidr for egress gateway
 	for _, iprange := range peer.EgressGatewayRanges { // go through each cidr for egress gateway
 		_, ipnet, err := net.ParseCIDR(iprange) // confirming it's valid cidr
 		_, ipnet, err := net.ParseCIDR(iprange) // confirming it's valid cidr
@@ -501,13 +507,13 @@ func getEgressIPs(node, peer *models.Node) []net.IPNet {
 			logger.Log(1, "could not parse gateway IP range. Not adding ", iprange)
 			logger.Log(1, "could not parse gateway IP range. Not adding ", iprange)
 			continue // if can't parse CIDR
 			continue // if can't parse CIDR
 		}
 		}
-		nodeEndpointArr := strings.Split(peer.Endpoint, ":") // getting the public ip of node
-		if ipnet.Contains(net.ParseIP(nodeEndpointArr[0])) { // ensuring egress gateway range does not contain endpoint of node
+		nodeEndpointArr := strings.Split(peer.Endpoint, ":")                     // getting the public ip of node
+		if ipnet.Contains(net.ParseIP(nodeEndpointArr[0])) && !internetGateway { // ensuring egress gateway range does not contain endpoint of node
 			logger.Log(2, "egress IP range of ", iprange, " overlaps with ", node.Endpoint, ", omitting")
 			logger.Log(2, "egress IP range of ", iprange, " overlaps with ", node.Endpoint, ", omitting")
 			continue // skip adding egress range if overlaps with node's ip
 			continue // skip adding egress range if overlaps with node's ip
 		}
 		}
 		// TODO: Could put in a lot of great logic to avoid conflicts / bad routes
 		// TODO: Could put in a lot of great logic to avoid conflicts / bad routes
-		if ipnet.Contains(net.ParseIP(node.LocalAddress)) { // ensuring egress gateway range does not contain public ip of node
+		if ipnet.Contains(net.ParseIP(node.LocalAddress)) && !internetGateway { // ensuring egress gateway range does not contain public ip of node
 			logger.Log(2, "egress IP range of ", iprange, " overlaps with ", node.LocalAddress, ", omitting")
 			logger.Log(2, "egress IP range of ", iprange, " overlaps with ", node.LocalAddress, ", omitting")
 			continue // skip adding egress range if overlaps with node's local ip
 			continue // skip adding egress range if overlaps with node's local ip
 		}
 		}

+ 6 - 0
logic/server.go

@@ -12,6 +12,7 @@ import (
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/servercfg"
 	"github.com/gravitl/netmaker/servercfg"
+	"golang.org/x/exp/slices"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 )
 
 
@@ -206,6 +207,11 @@ func GetServerPeers(serverNode *models.Node) ([]wgtypes.PeerConfig, bool, []stri
 	nodes, err := GetNetworkNodes(serverNode.Network)
 	nodes, err := GetNetworkNodes(serverNode.Network)
 	if err == nil {
 	if err == nil {
 		for _, node := range nodes {
 		for _, node := range nodes {
+			//if egress ranges is internet (0.0.0.0/0 or ::/0) remove as don't want server to use internet gateway
+			if node.IsEgressGateway == "yes" && (slices.Contains(node.EgressGatewayRanges, "0.0.0.0/0") || slices.Contains(node.EgressGatewayRanges, "::/0")) {
+				logger.Log(0, "skipping internet gateway for server")
+				continue
+			}
 			if node.IsEgressGateway == "yes" && !IsLocalServer(&node) {
 			if node.IsEgressGateway == "yes" && !IsLocalServer(&node) {
 				gateways = append(gateways, node.EgressGatewayRanges...)
 				gateways = append(gateways, node.EgressGatewayRanges...)
 			}
 			}

+ 15 - 14
models/node.go

@@ -76,20 +76,21 @@ type Node struct {
 	RelayAddrs              []string             `json:"relayaddrs" bson:"relayaddrs" yaml:"relayaddrs"`
 	RelayAddrs              []string             `json:"relayaddrs" bson:"relayaddrs" yaml:"relayaddrs"`
 	IngressGatewayRange     string               `json:"ingressgatewayrange" bson:"ingressgatewayrange" yaml:"ingressgatewayrange"`
 	IngressGatewayRange     string               `json:"ingressgatewayrange" bson:"ingressgatewayrange" yaml:"ingressgatewayrange"`
 	// IsStatic - refers to if the Endpoint is set manually or dynamically
 	// IsStatic - refers to if the Endpoint is set manually or dynamically
-	IsStatic      string      `json:"isstatic" bson:"isstatic" yaml:"isstatic" validate:"checkyesorno"`
-	UDPHolePunch  string      `json:"udpholepunch" bson:"udpholepunch" yaml:"udpholepunch" validate:"checkyesorno"`
-	DNSOn         string      `json:"dnson" bson:"dnson" yaml:"dnson" validate:"checkyesorno"`
-	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"`
-	Version       string      `json:"version" bson:"version" yaml:"version"`
-	Server        string      `json:"server" bson:"server" yaml:"server"`
-	TrafficKeys   TrafficKeys `json:"traffickeys" bson:"traffickeys" yaml:"traffickeys"`
-	FirewallInUse string      `json:"firewallinuse" bson:"firewallinuse" yaml:"firewallinuse"`
+	IsStatic        string      `json:"isstatic" bson:"isstatic" yaml:"isstatic" validate:"checkyesorno"`
+	UDPHolePunch    string      `json:"udpholepunch" bson:"udpholepunch" yaml:"udpholepunch" validate:"checkyesorno"`
+	DNSOn           string      `json:"dnson" bson:"dnson" yaml:"dnson" validate:"checkyesorno"`
+	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"`
+	Version         string      `json:"version" bson:"version" yaml:"version"`
+	Server          string      `json:"server" bson:"server" yaml:"server"`
+	TrafficKeys     TrafficKeys `json:"traffickeys" bson:"traffickeys" yaml:"traffickeys"`
+  FirewallInUse string      `json:"firewallinuse" bson:"firewallinuse" yaml:"firewallinuse"`
+	InternetGateway string      `json:"internetgateway" bson:"internetgateway" yaml:"internetgateway"`
 }
 }
 
 
 // NodesArray - used for node sorting
 // NodesArray - used for node sorting

+ 1 - 1
netclient/functions/join.go

@@ -85,7 +85,7 @@ func JoinNetwork(cfg *config.ClientConfig, privateKey string) error {
 		if cfg.Node.IsLocal == "yes" && cfg.Node.LocalAddress != "" {
 		if cfg.Node.IsLocal == "yes" && cfg.Node.LocalAddress != "" {
 			cfg.Node.Endpoint = cfg.Node.LocalAddress
 			cfg.Node.Endpoint = cfg.Node.LocalAddress
 		} else {
 		} else {
-			cfg.Node.Endpoint, err = ncutils.GetPublicIP()
+			cfg.Node.Endpoint, err = ncutils.GetPublicIP(cfg.Server.API)
 		}
 		}
 		if err != nil || cfg.Node.Endpoint == "" {
 		if err != nil || cfg.Node.Endpoint == "" {
 			logger.Log(0, "network:", cfg.Network, "error setting cfg.Node.Endpoint.")
 			logger.Log(0, "network:", cfg.Network, "error setting cfg.Node.Endpoint.")

+ 18 - 1
netclient/functions/mqhandlers.go

@@ -4,6 +4,7 @@ import (
 	"encoding/json"
 	"encoding/json"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
+	"net"
 	"os"
 	"os"
 	"runtime"
 	"runtime"
 	"strings"
 	"strings"
@@ -208,11 +209,27 @@ func UpdatePeers(client mqtt.Client, msg mqtt.Message) {
 	}
 	}
 
 
 	file := ncutils.GetNetclientPathSpecific() + cfg.Node.Interface + ".conf"
 	file := ncutils.GetNetclientPathSpecific() + cfg.Node.Interface + ".conf"
-	err = wireguard.UpdateWgPeers(file, peerUpdate.Peers)
+	internetGateway, err := wireguard.UpdateWgPeers(file, peerUpdate.Peers)
 	if err != nil {
 	if err != nil {
 		logger.Log(0, "error updating wireguard peers"+err.Error())
 		logger.Log(0, "error updating wireguard peers"+err.Error())
 		return
 		return
 	}
 	}
+	//check if internet gateway has changed
+	oldGateway, err := net.ResolveUDPAddr("udp", cfg.Node.InternetGateway)
+	if err != nil || (oldGateway == &net.UDPAddr{}) {
+		oldGateway = nil
+	}
+	if (internetGateway == nil && oldGateway != nil) || (internetGateway != nil && internetGateway != oldGateway) {
+		cfg.Node.InternetGateway = internetGateway.String()
+		if err := config.ModNodeConfig(&cfg.Node); err != nil {
+			logger.Log(0, "failed to save internet gateway", err.Error())
+		}
+		if err := wireguard.ApplyConf(&cfg.Node, cfg.Node.Interface, file); err != nil {
+			logger.Log(0, "error applying internet gateway", err.Error())
+		}
+		UpdateLocalListenPort(&cfg)
+		return
+	}
 	queryAddr := cfg.Node.PrimaryAddress()
 	queryAddr := cfg.Node.PrimaryAddress()
 
 
 	//err = wireguard.SyncWGQuickConf(cfg.Node.Interface, file)
 	//err = wireguard.SyncWGQuickConf(cfg.Node.Interface, file)

+ 1 - 1
netclient/functions/mqpublish.go

@@ -56,7 +56,7 @@ func checkin() {
 			nodeCfg.Node.FirewallInUse = models.FIREWALL_IPTABLES
 			nodeCfg.Node.FirewallInUse = models.FIREWALL_IPTABLES
 		}
 		}
 		if nodeCfg.Node.IsStatic != "yes" {
 		if nodeCfg.Node.IsStatic != "yes" {
-			extIP, err := ncutils.GetPublicIP()
+			extIP, err := ncutils.GetPublicIP(nodeCfg.Server.API)
 			if err != nil {
 			if err != nil {
 				logger.Log(1, "error encountered checking public ip addresses: ", err.Error())
 				logger.Log(1, "error encountered checking public ip addresses: ", err.Error())
 			}
 			}

+ 6 - 2
netclient/ncutils/netclientutils.go

@@ -135,9 +135,9 @@ func IsEmptyRecord(err error) bool {
 }
 }
 
 
 // GetPublicIP - gets public ip
 // GetPublicIP - gets public ip
-func GetPublicIP() (string, error) {
+func GetPublicIP(api string) (string, error) {
 
 
-	iplist := []string{"https://ip.server.gravitl.com", "https://ifconfig.me", "https://api.ipify.org", "https://ipinfo.io/ip"}
+	iplist := []string{"https://ip.client.gravitl.com", "https://ifconfig.me", "https://api.ipify.org", "https://ipinfo.io/ip"}
 
 
 	for network, ipService := range global_settings.PublicIPServices {
 	for network, ipService := range global_settings.PublicIPServices {
 		logger.Log(3, "User provided public IP service defined for network", network, "is", ipService)
 		logger.Log(3, "User provided public IP service defined for network", network, "is", ipService)
@@ -145,6 +145,10 @@ func GetPublicIP() (string, error) {
 		// prepend the user-specified service so it's checked first
 		// prepend the user-specified service so it's checked first
 		iplist = append([]string{ipService}, iplist...)
 		iplist = append([]string{ipService}, iplist...)
 	}
 	}
+	if api != "" {
+		api = "https://" + api + "/api/getip"
+		iplist = append([]string{api}, iplist...)
+	}
 
 
 	endpoint := ""
 	endpoint := ""
 	var err error
 	var err error

+ 8 - 5
netclient/wireguard/common.go

@@ -319,7 +319,6 @@ func ApplyConf(node *models.Node, ifacename string, confPath string) error {
 }
 }
 
 
 // WriteWgConfig - creates a wireguard config file
 // WriteWgConfig - creates a wireguard config file
-//func WriteWgConfig(cfg *config.ClientConfig, privateKey string, peers []wgtypes.PeerConfig) error {
 func WriteWgConfig(node *models.Node, privateKey string, peers []wgtypes.PeerConfig) error {
 func WriteWgConfig(node *models.Node, privateKey string, peers []wgtypes.PeerConfig) error {
 	options := ini.LoadOptions{
 	options := ini.LoadOptions{
 		AllowNonUniqueSections: true,
 		AllowNonUniqueSections: true,
@@ -382,14 +381,15 @@ func WriteWgConfig(node *models.Node, privateKey string, peers []wgtypes.PeerCon
 }
 }
 
 
 // UpdateWgPeers - updates the peers of a network
 // UpdateWgPeers - updates the peers of a network
-func UpdateWgPeers(file string, peers []wgtypes.PeerConfig) error {
+func UpdateWgPeers(file string, peers []wgtypes.PeerConfig) (*net.UDPAddr, error) {
+	var internetGateway *net.UDPAddr
 	options := ini.LoadOptions{
 	options := ini.LoadOptions{
 		AllowNonUniqueSections: true,
 		AllowNonUniqueSections: true,
 		AllowShadows:           true,
 		AllowShadows:           true,
 	}
 	}
 	wireguard, err := ini.LoadSources(options, file)
 	wireguard, err := ini.LoadSources(options, file)
 	if err != nil {
 	if err != nil {
-		return err
+		return internetGateway, err
 	}
 	}
 	//delete the peers sections as they are going to be replaced
 	//delete the peers sections as they are going to be replaced
 	wireguard.DeleteSection(section_peers)
 	wireguard.DeleteSection(section_peers)
@@ -408,6 +408,9 @@ func UpdateWgPeers(file string, peers []wgtypes.PeerConfig) error {
 				}
 				}
 			}
 			}
 			wireguard.SectionWithIndex(section_peers, i).Key("AllowedIps").SetValue(allowedIPs)
 			wireguard.SectionWithIndex(section_peers, i).Key("AllowedIps").SetValue(allowedIPs)
+			if strings.Contains(allowedIPs, "0.0.0.0/0") || strings.Contains(allowedIPs, "::/0") {
+				internetGateway = peer.Endpoint
+			}
 		}
 		}
 		if peer.Endpoint != nil {
 		if peer.Endpoint != nil {
 			wireguard.SectionWithIndex(section_peers, i).Key("Endpoint").SetValue(peer.Endpoint.String())
 			wireguard.SectionWithIndex(section_peers, i).Key("Endpoint").SetValue(peer.Endpoint.String())
@@ -417,9 +420,9 @@ func UpdateWgPeers(file string, peers []wgtypes.PeerConfig) error {
 		}
 		}
 	}
 	}
 	if err := wireguard.SaveTo(file); err != nil {
 	if err := wireguard.SaveTo(file); err != nil {
-		return err
+		return internetGateway, err
 	}
 	}
-	return nil
+	return internetGateway, nil
 }
 }
 
 
 // UpdateWgInterface - updates the interface section of a wireguard config file
 // UpdateWgInterface - updates the interface section of a wireguard config file

+ 4 - 4
servercfg/serverconf.go

@@ -430,20 +430,20 @@ func GetPublicIP() (string, error) {
 	iplist := []string{"https://ip.server.gravitl.com", "https://ifconfig.me", "https://api.ipify.org", "https://ipinfo.io/ip"}
 	iplist := []string{"https://ip.server.gravitl.com", "https://ifconfig.me", "https://api.ipify.org", "https://ipinfo.io/ip"}
 	publicIpService := os.Getenv("PUBLIC_IP_SERVICE")
 	publicIpService := os.Getenv("PUBLIC_IP_SERVICE")
 	if publicIpService != "" {
 	if publicIpService != "" {
-		logger.Log(3, "User (environment variable) provided public IP service is", publicIpService)
+		logger.Log(4, "User (environment variable) provided public IP service is", publicIpService)
 
 
 		// prepend the user-specified service so it's checked first
 		// prepend the user-specified service so it's checked first
 		iplist = append([]string{publicIpService}, iplist...)
 		iplist = append([]string{publicIpService}, iplist...)
 	} else if config.Config.Server.PublicIPService != "" {
 	} else if config.Config.Server.PublicIPService != "" {
 		publicIpService = config.Config.Server.PublicIPService
 		publicIpService = config.Config.Server.PublicIPService
-		logger.Log(3, "User (config file) provided public IP service is", publicIpService)
+		logger.Log(4, "User (config file) provided public IP service is", publicIpService)
 
 
 		// prepend the user-specified service so it's checked first
 		// prepend the user-specified service so it's checked first
 		iplist = append([]string{publicIpService}, iplist...)
 		iplist = append([]string{publicIpService}, iplist...)
 	}
 	}
 
 
 	for _, ipserver := range iplist {
 	for _, ipserver := range iplist {
-		logger.Log(3, "Running public IP check with service", ipserver)
+		logger.Log(4, "Running public IP check with service", ipserver)
 		client := &http.Client{
 		client := &http.Client{
 			Timeout: time.Second * 10,
 			Timeout: time.Second * 10,
 		}
 		}
@@ -458,7 +458,7 @@ func GetPublicIP() (string, error) {
 				continue
 				continue
 			}
 			}
 			endpoint = string(bodyBytes)
 			endpoint = string(bodyBytes)
-			logger.Log(3, "Public IP address is", endpoint)
+			logger.Log(4, "Public IP address is", endpoint)
 			break
 			break
 		}
 		}
 	}
 	}