diff --git a/controllers/config/dnsconfig/netmaker.hosts b/controllers/config/dnsconfig/netmaker.hosts index 45eab425..655eaef6 100644 --- a/controllers/config/dnsconfig/netmaker.hosts +++ b/controllers/config/dnsconfig/netmaker.hosts @@ -1 +1,2 @@ -10.0.0.2 testnode.skynet myhost.skynet +10.0.0.1 testnode.skynet +10.0.0.2 myhost.skynet diff --git a/logic/gateway.go b/logic/gateway.go index 4e129251..f7944edb 100644 --- a/logic/gateway.go +++ b/logic/gateway.go @@ -3,6 +3,7 @@ package logic import ( "encoding/json" "errors" + "fmt" "strings" "time" @@ -30,17 +31,25 @@ func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, erro node.IsEgressGateway = "yes" node.EgressGatewayRanges = gateway.Ranges node.EgressGatewayNatEnabled = gateway.NatEnabled + node.EgressGatewayRequest = gateway // store entire request for use when preserving the egress gateway postUpCmd := "" postDownCmd := "" + logger.Log(3, "creating egress gateway firewall in use is '", node.FirewallInUse, "'") if node.OS == "linux" { - postUpCmd = "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT; " - postUpCmd += "iptables -A FORWARD -o " + node.Interface + " -j ACCEPT" - postDownCmd = "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; " - postDownCmd += "iptables -D FORWARD -o " + node.Interface + " -j ACCEPT" + switch node.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(node.Interface, gateway.Interface, node.EgressGatewayNatEnabled) - if node.EgressGatewayNatEnabled == "yes" { - postUpCmd += "; iptables -t nat -A POSTROUTING -o " + gateway.Interface + " -j MASQUERADE" - postDownCmd += "; iptables -t nat -D POSTROUTING -o " + gateway.Interface + " -j MASQUERADE" + default: // iptables assumed + logger.Log(3, "creating egress gateway nftables is not present") + postUpCmd, postDownCmd = firewallIPTablesCommandsCreateEgress(node.Interface, gateway.Interface, node.EgressGatewayNatEnabled) } } if node.OS == "freebsd" { @@ -115,23 +124,27 @@ func DeleteEgressGateway(network, nodeid string) (models.Node, error) { node.IsEgressGateway = "no" 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 = "" + + logger.Log(3, "deleting egress gateway firewall in use is '", node.FirewallInUse, "'") if node.IsIngressGateway == "yes" { // check if node is still an ingress gateway before completely deleting postdown/up rules + // still have an ingress gateway so preserve it if node.OS == "linux" { - node.PostUp = "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT ; " - node.PostUp += "iptables -A FORWARD -o " + node.Interface + " -j ACCEPT ; " - node.PostUp += "iptables -t nat -A POSTROUTING -o " + node.Interface + " -j MASQUERADE" - node.PostDown = "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT ; " - node.PostDown += "iptables -D FORWARD -o " + node.Interface + " -j ACCEPT ; " - node.PostDown += "iptables -t nat -D POSTROUTING -o " + node.Interface + " -j MASQUERADE" - } - if node.OS == "freebsd" { - node.PostUp = "" - node.PostDown = "ipfw delete 64000 ; " - node.PostDown += "ipfw delete 65534 ; " - node.PostDown += "kldunload ipfw_nat ipfw" + switch node.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(node.Interface) + default: + logger.Log(3, "deleting egress gateway nftables is not present") + node.PostUp, node.PostDown = firewallIPTablesCommandsCreateIngress(node.Interface) + } } + // no need to preserve ingress gateway on FreeBSD as ingress is not supported on that OS } node.SetLastModified() @@ -151,6 +164,7 @@ func DeleteEgressGateway(network, nodeid string) (models.Node, error) { // CreateIngressGateway - creates an ingress gateway func CreateIngressGateway(netid string, nodeid string) (models.Node, error) { + var postUpCmd, postDownCmd string node, err := GetNodeByID(nodeid) if node.OS != "linux" { // add in darwin later return models.Node{}, errors.New(node.OS + " is unsupported for ingress gateways") @@ -166,12 +180,18 @@ func CreateIngressGateway(netid string, nodeid string) (models.Node, error) { } node.IsIngressGateway = "yes" node.IngressGatewayRange = network.AddressRange - postUpCmd := "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT ; " - postUpCmd += "iptables -A FORWARD -o " + node.Interface + " -j ACCEPT ; " - postUpCmd += "iptables -t nat -A POSTROUTING -o " + node.Interface + " -j MASQUERADE" - postDownCmd := "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT ; " - postDownCmd += "iptables -D FORWARD -o " + node.Interface + " -j ACCEPT ; " - postDownCmd += "iptables -t nat -D POSTROUTING -o " + node.Interface + " -j MASQUERADE" + logger.Log(3, "creating ingress gateway firewall in use is '", node.FirewallInUse, "'") + switch node.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(node.Interface) + default: + logger.Log(3, "creating ingress gateway using nftables is not present") + postUpCmd, postDownCmd = firewallIPTablesCommandsCreateIngress(node.Interface) + } + if node.PostUp != "" { if !strings.Contains(node.PostUp, postUpCmd) { postUpCmd = node.PostUp + "; " + postUpCmd @@ -214,12 +234,26 @@ func DeleteIngressGateway(networkName string, nodeid string) (models.Node, error if err = DeleteGatewayExtClients(node.ID, networkName); err != nil { return models.Node{}, err } + logger.Log(3, "deleting ingress gateway") node.UDPHolePunch = network.DefaultUDPHolePunch node.LastModified = time.Now().Unix() node.IsIngressGateway = "no" node.IngressGatewayRange = "" + // default to removing postup and postdown + node.PostUp = "" + node.PostDown = "" + + logger.Log(3, "deleting ingress gateway firewall in use is '", node.FirewallInUse, "' and isEgressGateway is", node.IsEgressGateway) + if node.EgressGatewayRequest.NodeID != "" { + _, err := CreateEgressGateway(node.EgressGatewayRequest) + if err != nil { + logger.Log(0, fmt.Sprintf("failed to create egress gateway on node [%s] on network [%s]: %v", + node.EgressGatewayRequest.NodeID, node.EgressGatewayRequest.NetID, err)) + } + } + data, err := json.Marshal(&node) if err != nil { return models.Node{}, err @@ -248,3 +282,73 @@ 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) { + 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 delete rule ip filter FORWARD iifname " + networkInterface + " counter accept ; " + postDown += "nft delete rule ip filter FORWARD oifname " + networkInterface + " counter accept ; " + postDown += "nft delete rule ip nat POSTROUTING oifname " + networkInterface + " counter masquerade" + + 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, egressNatEnabled string) (string, string) { + 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 ; " + + postDown := "nft delete rule ip filter FORWARD iifname " + networkInterface + " counter accept ; " + postDown += "nft delete rule ip filter FORWARD oifname " + networkInterface + " counter accept ; " + + if egressNatEnabled == "yes" { + postUp += "nft add table nat ; " + postUp += "nft add chain nat POSTROUTING ; " + postUp += "nft add rule ip nat POSTROUTING oifname " + gatewayInterface + " counter masquerade ;" + + postDown += "nft delete rule ip nat POSTROUTING oifname " + gatewayInterface + " counter masquerade ;" + } + + return postUp, postDown +} + +// firewallIPTablesCommandsCreateIngress - used to centralize firewall command maintenance for creating an ingress gateway using the iptables firewall. +func firewallIPTablesCommandsCreateIngress(networkInterface string) (string, string) { + 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" + + 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 string) (string, string) { + + 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 == "yes" { + postUp += "; iptables -t nat -A POSTROUTING -o " + gatewayInterface + " -j MASQUERADE" + postDown += "; iptables -t nat -D POSTROUTING -o " + gatewayInterface + " -j MASQUERADE" + } + + return postUp, postDown + +} diff --git a/logic/nodes.go b/logic/nodes.go index 66b47be5..d5123ffe 100644 --- a/logic/nodes.go +++ b/logic/nodes.go @@ -427,6 +427,7 @@ func SetNodeDefaults(node *models.Node) { node.SetDefaultIngressGateway() node.SetDefaulIsPending() node.SetDefaultMTU() + node.SetDefaultNFTablesPresent() node.SetDefaultIsRelayed() node.SetDefaultIsRelay() node.SetDefaultIsDocker() diff --git a/models/node.go b/models/node.go index 6edd0199..5f84e59f 100644 --- a/models/node.go +++ b/models/node.go @@ -28,6 +28,10 @@ const ( NODE_NOOP = "noop" // NODE_FORCE_UPDATE - indicates a node should pull all changes NODE_FORCE_UPDATE = "force" + // FIREWALL_IPTABLES - indicates that iptables is the firewall in use + FIREWALL_IPTABLES = "iptables" + // FIREWALL_NFTABLES - indicates nftables is in use (Linux only) + FIREWALL_NFTABLES = "nftables" ) var seededRand *rand.Rand = rand.New( @@ -35,55 +39,57 @@ var seededRand *rand.Rand = rand.New( // Node - struct for node model type Node struct { - ID string `json:"id,omitempty" bson:"id,omitempty" yaml:"id,omitempty" validate:"required,min=5" validate:"id_unique` - Address string `json:"address" bson:"address" yaml:"address" validate:"omitempty,ipv4"` - Address6 string `json:"address6" bson:"address6" yaml:"address6" validate:"omitempty,ipv6"` - LocalAddress string `json:"localaddress" bson:"localaddress" yaml:"localaddress" validate:"omitempty,ip"` - Name string `json:"name" bson:"name" yaml:"name" validate:"omitempty,max=62,in_charset"` - NetworkSettings Network `json:"networksettings" bson:"networksettings" yaml:"networksettings" validate:"-"` - ListenPort int32 `json:"listenport" bson:"listenport" yaml:"listenport" validate:"omitempty,numeric,min=1024,max=65535"` - LocalListenPort int32 `json:"locallistenport" bson:"locallistenport" yaml:"locallistenport" 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"` - AccessKey string `json:"accesskey" bson:"accesskey" yaml:"accesskey"` - Interface string `json:"interface" bson:"interface" yaml:"interface"` - LastModified int64 `json:"lastmodified" bson:"lastmodified" yaml:"lastmodified"` - ExpirationDateTime int64 `json:"expdatetime" bson:"expdatetime" yaml:"expdatetime"` - LastPeerUpdate int64 `json:"lastpeerupdate" bson:"lastpeerupdate" yaml:"lastpeerupdate"` - LastCheckIn int64 `json:"lastcheckin" bson:"lastcheckin" yaml:"lastcheckin"` - MacAddress string `json:"macaddress" bson:"macaddress" yaml:"macaddress"` - Password string `json:"password" bson:"password" yaml:"password" validate:"required,min=6"` - Network string `json:"network" bson:"network" yaml:"network" validate:"network_exists"` - IsRelayed string `json:"isrelayed" bson:"isrelayed" yaml:"isrelayed"` - IsPending string `json:"ispending" bson:"ispending" yaml:"ispending"` - IsRelay string `json:"isrelay" bson:"isrelay" yaml:"isrelay" validate:"checkyesorno"` - IsDocker string `json:"isdocker" bson:"isdocker" yaml:"isdocker" validate:"checkyesorno"` - IsK8S string `json:"isk8s" bson:"isk8s" yaml:"isk8s" validate:"checkyesorno"` - IsEgressGateway string `json:"isegressgateway" bson:"isegressgateway" yaml:"isegressgateway"` - IsIngressGateway string `json:"isingressgateway" bson:"isingressgateway" yaml:"isingressgateway"` - EgressGatewayRanges []string `json:"egressgatewayranges" bson:"egressgatewayranges" yaml:"egressgatewayranges"` - EgressGatewayNatEnabled string `json:"egressgatewaynatenabled" bson:"egressgatewaynatenabled" yaml:"egressgatewaynatenabled"` - RelayAddrs []string `json:"relayaddrs" bson:"relayaddrs" yaml:"relayaddrs"` - IngressGatewayRange string `json:"ingressgatewayrange" bson:"ingressgatewayrange" yaml:"ingressgatewayrange"` + ID string `json:"id,omitempty" bson:"id,omitempty" yaml:"id,omitempty" validate:"required,min=5" validate:"id_unique` + Address string `json:"address" bson:"address" yaml:"address" validate:"omitempty,ipv4"` + Address6 string `json:"address6" bson:"address6" yaml:"address6" validate:"omitempty,ipv6"` + LocalAddress string `json:"localaddress" bson:"localaddress" yaml:"localaddress" validate:"omitempty,ip"` + Name string `json:"name" bson:"name" yaml:"name" validate:"omitempty,max=62,in_charset"` + NetworkSettings Network `json:"networksettings" bson:"networksettings" yaml:"networksettings" validate:"-"` + ListenPort int32 `json:"listenport" bson:"listenport" yaml:"listenport" validate:"omitempty,numeric,min=1024,max=65535"` + LocalListenPort int32 `json:"locallistenport" bson:"locallistenport" yaml:"locallistenport" 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"` + AccessKey string `json:"accesskey" bson:"accesskey" yaml:"accesskey"` + Interface string `json:"interface" bson:"interface" yaml:"interface"` + LastModified int64 `json:"lastmodified" bson:"lastmodified" yaml:"lastmodified"` + ExpirationDateTime int64 `json:"expdatetime" bson:"expdatetime" yaml:"expdatetime"` + LastPeerUpdate int64 `json:"lastpeerupdate" bson:"lastpeerupdate" yaml:"lastpeerupdate"` + LastCheckIn int64 `json:"lastcheckin" bson:"lastcheckin" yaml:"lastcheckin"` + MacAddress string `json:"macaddress" bson:"macaddress" yaml:"macaddress"` + Password string `json:"password" bson:"password" yaml:"password" validate:"required,min=6"` + Network string `json:"network" bson:"network" yaml:"network" validate:"network_exists"` + IsRelayed string `json:"isrelayed" bson:"isrelayed" yaml:"isrelayed"` + IsPending string `json:"ispending" bson:"ispending" yaml:"ispending"` + IsRelay string `json:"isrelay" bson:"isrelay" yaml:"isrelay" validate:"checkyesorno"` + IsDocker string `json:"isdocker" bson:"isdocker" yaml:"isdocker" validate:"checkyesorno"` + IsK8S string `json:"isk8s" bson:"isk8s" yaml:"isk8s" validate:"checkyesorno"` + IsEgressGateway string `json:"isegressgateway" bson:"isegressgateway" yaml:"isegressgateway"` + IsIngressGateway string `json:"isingressgateway" bson:"isingressgateway" yaml:"isingressgateway"` + EgressGatewayRanges []string `json:"egressgatewayranges" bson:"egressgatewayranges" yaml:"egressgatewayranges"` + EgressGatewayNatEnabled string `json:"egressgatewaynatenabled" bson:"egressgatewaynatenabled" yaml:"egressgatewaynatenabled"` + EgressGatewayRequest EgressGatewayRequest `json:"egressgatewayrequest" bson:"egressgatewayrequest" yaml:"egressgatewayrequest"` + RelayAddrs []string `json:"relayaddrs" bson:"relayaddrs" yaml:"relayaddrs"` + IngressGatewayRange string `json:"ingressgatewayrange" bson:"ingressgatewayrange" yaml:"ingressgatewayrange"` // 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"` + 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"` } // NodesArray - used for node sorting @@ -119,6 +125,13 @@ func (node *Node) SetDefaultMTU() { } } +// Node.SetDefaultNFTablesPresent - sets default for nftables check +func (node *Node) SetDefaultNFTablesPresent() { + if node.FirewallInUse == "" { + node.FirewallInUse = FIREWALL_IPTABLES // default to iptables + } +} + // Node.SetDefaulIsPending - sets ispending default func (node *Node) SetDefaulIsPending() { if node.IsPending == "" { @@ -254,7 +267,7 @@ func (node *Node) SetDefaultName() { } // Node.Fill - fills other node data into calling node data if not set on calling node -func (newNode *Node) Fill(currentNode *Node) { +func (newNode *Node) Fill(currentNode *Node) { // TODO add new field for nftables present newNode.ID = currentNode.ID if newNode.Address == "" { diff --git a/netclient/functions/join.go b/netclient/functions/join.go index 1d69fcfd..09ca176a 100644 --- a/netclient/functions/join.go +++ b/netclient/functions/join.go @@ -114,7 +114,17 @@ func JoinNetwork(cfg *config.ClientConfig, privateKey string) error { if ncutils.IsFreeBSD() { cfg.Node.UDPHolePunch = "no" + cfg.Node.FirewallInUse = models.FIREWALL_IPTABLES // nftables not supported by FreeBSD } + + if cfg.Node.FirewallInUse == "" { + if ncutils.IsNFTablesPresent() { + cfg.Node.FirewallInUse = models.FIREWALL_NFTABLES + } else { + cfg.Node.FirewallInUse = models.FIREWALL_IPTABLES + } + } + // make sure name is appropriate, if not, give blank name cfg.Node.Name = formatName(cfg.Node) cfg.Node.OS = runtime.GOOS diff --git a/netclient/functions/mqpublish.go b/netclient/functions/mqpublish.go index 4f90f2ed..d72fc349 100644 --- a/netclient/functions/mqpublish.go +++ b/netclient/functions/mqpublish.go @@ -13,6 +13,7 @@ import ( "github.com/cloverstd/tcping/ping" "github.com/gravitl/netmaker/logger" + "github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/netclient/auth" "github.com/gravitl/netmaker/netclient/config" "github.com/gravitl/netmaker/netclient/ncutils" @@ -43,6 +44,17 @@ func checkin() { var nodeCfg config.ClientConfig nodeCfg.Network = network nodeCfg.ReadConfig() + // check for nftables present if on Linux + if ncutils.IsLinux() { + if ncutils.IsNFTablesPresent() { + nodeCfg.Node.FirewallInUse = models.FIREWALL_NFTABLES + } else { + nodeCfg.Node.FirewallInUse = models.FIREWALL_IPTABLES + } + } else { + // defaults to iptables for now, may need another default for non-Linux OSes + nodeCfg.Node.FirewallInUse = models.FIREWALL_IPTABLES + } if nodeCfg.Node.IsStatic != "yes" { extIP, err := ncutils.GetPublicIP() if err != nil { diff --git a/netclient/ncutils/netclientutils.go b/netclient/ncutils/netclientutils.go index 2833d22b..183773dd 100644 --- a/netclient/ncutils/netclientutils.go +++ b/netclient/ncutils/netclientutils.go @@ -110,6 +110,16 @@ func GetWireGuard() string { return "wg" } +// IsNFTablesPresent - returns true if nftables is present, false otherwise. +// Does not consider OS, up to the caller to determine if the OS supports nftables/whether this check is valid. +func IsNFTablesPresent() bool { + var nftFound bool + + nftFound = FileExists("/usr/sbin/nft") + logger.Log(3, "nftables found:", strconv.FormatBool(nftFound)) + return nftFound +} + // IsKernel - checks if running kernel WireGuard func IsKernel() bool { //TODO