NET-710: Internet Gws Re-Design (#2718)

* add internet gateway to client gateway

* migration func to remove internet egress range from egress gateway

* add internet gateways ranges to firewall update

* add internet gw ranges to extcleint conf

* add ipv6 internet address

* remove failover field from ingress req

* only let normal to be created on PRO (#2716)

* feat(NET-805): send internet gw props to rac

* set inet gw field on node update api

* move internet gws to EE

---------

Co-authored-by: the_aceix <aceixsmartx@gmail.com>
This commit is contained in:
Abhishek K 2023-12-06 23:57:58 +04:00 committed by GitHub
parent 03db704436
commit 530dbdc65c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 150 additions and 57 deletions

View file

@ -216,18 +216,28 @@ func getExtClientConf(w http.ResponseWriter, r *http.Request) {
} else {
gwendpoint = fmt.Sprintf("%s:%d", host.EndpointIP.String(), host.ListenPort)
}
newAllowedIPs := network.AddressRange
if newAllowedIPs != "" && network.AddressRange6 != "" {
newAllowedIPs += ","
}
if network.AddressRange6 != "" {
newAllowedIPs += network.AddressRange6
}
if egressGatewayRanges, err := logic.GetEgressRangesOnNetwork(&client); err == nil {
for _, egressGatewayRange := range egressGatewayRanges {
newAllowedIPs += "," + egressGatewayRange
var newAllowedIPs string
if logic.IsInternetGw(gwnode) {
egressrange := "0.0.0.0/0"
if gwnode.Address6.IP != nil && client.Address6 != "" {
egressrange += "," + "::/0"
}
newAllowedIPs = egressrange
} else {
newAllowedIPs = network.AddressRange
if newAllowedIPs != "" && network.AddressRange6 != "" {
newAllowedIPs += ","
}
if network.AddressRange6 != "" {
newAllowedIPs += network.AddressRange6
}
if egressGatewayRanges, err := logic.GetEgressRangesOnNetwork(&client); err == nil {
for _, egressGatewayRange := range egressGatewayRanges {
newAllowedIPs += "," + egressGatewayRange
}
}
}
defaultDNS := ""
if client.DNS != "" {
defaultDNS = "DNS = " + client.DNS

View file

@ -10,6 +10,16 @@ import (
"github.com/gravitl/netmaker/models"
)
var (
// SetInternetGw - sets the node as internet gw based on flag bool
SetInternetGw = func(node *models.Node, flag bool) {
}
// IsInternetGw - checks if node is acting as internet gw
IsInternetGw = func(node models.Node) bool {
return false
}
)
// GetInternetGateways - gets all the nodes that are internet gateways
func GetInternetGateways() ([]models.Node, error) {
nodes, err := GetAllNodes()
@ -78,12 +88,8 @@ func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, erro
}
for i := len(gateway.Ranges) - 1; i >= 0; i-- {
// check if internet gateway IPv4
if gateway.Ranges[i] == "0.0.0.0/0" && FreeTier {
return models.Node{}, fmt.Errorf("currently IPv4 internet gateways are not supported on the free tier: %s", gateway.Ranges[i])
}
// check if internet gateway IPv6
if gateway.Ranges[i] == "::/0" {
return models.Node{}, fmt.Errorf("currently IPv6 internet gateways are not supported: %s", gateway.Ranges[i])
if gateway.Ranges[i] == "0.0.0.0/0" || gateway.Ranges[i] == "::/0" {
return models.Node{}, fmt.Errorf("create internet gateways on the remote client gateway")
}
normalized, err := NormalizeCIDR(gateway.Ranges[i])
if err != nil {
@ -163,6 +169,7 @@ func CreateIngressGateway(netid string, nodeid string, ingress models.IngressReq
return models.Node{}, err
}
node.IsIngressGateway = true
SetInternetGw(&node, ingress.IsInternetGateway)
node.IngressGatewayRange = network.AddressRange
node.IngressGatewayRange6 = network.AddressRange6
node.IngressDNS = ingress.ExtclientDNS
@ -215,6 +222,7 @@ func DeleteIngressGateway(nodeid string) (models.Node, []models.ExtClient, error
logger.Log(3, "deleting ingress gateway")
node.LastModified = time.Now()
node.IsIngressGateway = false
node.IsInternetGateway = false
node.IngressGatewayRange = ""
err = UpsertNode(&node)
if err != nil {

View file

@ -241,8 +241,18 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N
logger.Log(1, "error retrieving external clients:", err.Error())
}
}
addedInetGwRanges := false
if node.IsEgressGateway && node.EgressGatewayRequest.NatEnabled == "yes" && len(node.EgressGatewayRequest.Ranges) > 0 {
hostPeerUpdate.FwUpdate.IsEgressGw = true
if IsInternetGw(node) {
hostPeerUpdate.FwUpdate.IsEgressGw = true
egressrange := []string{"0.0.0.0/0"}
if node.Address6.IP != nil {
egressrange = append(egressrange, "::/0")
}
node.EgressGatewayRequest.Ranges = append(node.EgressGatewayRequest.Ranges, egressrange...)
addedInetGwRanges = true
}
hostPeerUpdate.FwUpdate.EgressInfo[node.ID.String()] = models.EgressInfo{
EgressID: node.ID.String(),
Network: node.PrimaryNetworkRange(),
@ -252,6 +262,28 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N
},
EgressGWCfg: node.EgressGatewayRequest,
}
}
if IsInternetGw(node) && !addedInetGwRanges {
hostPeerUpdate.FwUpdate.IsEgressGw = true
egressrange := []string{"0.0.0.0/0"}
if node.Address6.IP != nil {
egressrange = append(egressrange, "::/0")
}
hostPeerUpdate.FwUpdate.EgressInfo[node.ID.String()] = models.EgressInfo{
EgressID: node.ID.String(),
Network: node.PrimaryAddressIPNet(),
EgressGwAddr: net.IPNet{
IP: net.ParseIP(node.PrimaryAddress()),
Mask: getCIDRMaskFromAddr(node.PrimaryAddress()),
},
EgressGWCfg: models.EgressGatewayRequest{
NodeID: node.ID.String(),
NetID: node.Network,
NatEnabled: "yes",
Ranges: egressrange,
},
}
}
}
// == post peer calculations ==

View file

@ -18,6 +18,7 @@ func Run() {
updateEnrollmentKeys()
assignSuperAdmin()
updateHosts()
updateNodes()
}
func assignSuperAdmin() {
@ -137,3 +138,32 @@ func updateHosts() {
}
}
}
func updateNodes() {
nodes, err := logic.GetAllNodes()
if err != nil {
slog.Error("migration failed for nodes", "error", err)
return
}
for _, node := range nodes {
if node.IsEgressGateway {
egressRanges, update := removeInterGw(node.EgressGatewayRanges)
if update {
node.EgressGatewayRequest.Ranges = egressRanges
node.EgressGatewayRanges = egressRanges
logic.UpsertNode(&node)
}
}
}
}
func removeInterGw(egressRanges []string) ([]string, bool) {
update := false
for i := len(egressRanges) - 1; i >= 0; i-- {
if egressRanges[i] == "0.0.0.0/0" || egressRanges[i] == "::/0" {
update = true
egressRanges = append(egressRanges[:i], egressRanges[i+1:]...)
}
}
return egressRanges, update
}

View file

@ -28,6 +28,7 @@ type ApiNode struct {
RelayedNodes []string `json:"relaynodes" yaml:"relayedNodes"`
IsEgressGateway bool `json:"isegressgateway"`
IsIngressGateway bool `json:"isingressgateway"`
IsInternetGateway bool `json:"isinternetgateway" yaml:"isinternetgateway"`
EgressGatewayRanges []string `json:"egressgatewayranges"`
EgressGatewayNatEnabled bool `json:"egressgatewaynatenabled"`
DNSOn bool `json:"dnson"`
@ -67,6 +68,7 @@ func (a *ApiNode) ConvertToServerNode(currentNode *Node) *Node {
convertedNode.IngressGatewayRange6 = currentNode.IngressGatewayRange6
convertedNode.DNSOn = a.DNSOn
convertedNode.IngressDNS = a.IngressDns
convertedNode.IsInternetGateway = a.IsInternetGateway
convertedNode.EgressGatewayRequest = currentNode.EgressGatewayRequest
convertedNode.EgressGatewayNatEnabled = currentNode.EgressGatewayNatEnabled
convertedNode.RelayedNodes = a.RelayedNodes
@ -88,10 +90,6 @@ func (a *ApiNode) ConvertToServerNode(currentNode *Node) *Node {
} else if !isEmptyAddr(currentNode.LocalAddress.String()) {
convertedNode.LocalAddress = currentNode.LocalAddress
}
udpAddr, err := net.ResolveUDPAddr("udp", a.InternetGateway)
if err == nil {
convertedNode.InternetGateway = udpAddr
}
ip, addr, err := net.ParseCIDR(a.Address)
if err == nil {
convertedNode.Address = *addr
@ -150,13 +148,13 @@ func (nm *Node) ConvertToAPINode() *ApiNode {
apiNode.DNSOn = nm.DNSOn
apiNode.IngressDns = nm.IngressDNS
apiNode.Server = nm.Server
apiNode.InternetGateway = nm.InternetGateway.String()
if isEmptyAddr(apiNode.InternetGateway) {
apiNode.InternetGateway = ""
}
apiNode.Connected = nm.Connected
apiNode.PendingDelete = nm.PendingDelete
apiNode.DefaultACL = nm.DefaultACL
apiNode.IsInternetGateway = nm.IsInternetGateway
apiNode.IsFailOver = nm.IsFailOver
apiNode.FailOverPeers = nm.FailOverPeers
apiNode.FailedOverBy = nm.FailedOverBy

View file

@ -54,27 +54,27 @@ type Iface struct {
// CommonNode - represents a commonn node data elements shared by netmaker and netclient
type CommonNode struct {
ID uuid.UUID `json:"id" yaml:"id"`
HostID uuid.UUID `json:"hostid" yaml:"hostid"`
Network string `json:"network" yaml:"network"`
NetworkRange net.IPNet `json:"networkrange" yaml:"networkrange"`
NetworkRange6 net.IPNet `json:"networkrange6" yaml:"networkrange6"`
InternetGateway *net.UDPAddr `json:"internetgateway" yaml:"internetgateway"`
Server string `json:"server" yaml:"server"`
Connected bool `json:"connected" yaml:"connected"`
Address net.IPNet `json:"address" yaml:"address"`
Address6 net.IPNet `json:"address6" yaml:"address6"`
Action string `json:"action" yaml:"action"`
LocalAddress net.IPNet `json:"localaddress" yaml:"localaddress"`
IsEgressGateway bool `json:"isegressgateway" yaml:"isegressgateway"`
EgressGatewayRanges []string `json:"egressgatewayranges" bson:"egressgatewayranges" yaml:"egressgatewayranges"`
IsIngressGateway bool `json:"isingressgateway" yaml:"isingressgateway"`
IsRelayed bool `json:"isrelayed" bson:"isrelayed" yaml:"isrelayed"`
RelayedBy string `json:"relayedby" bson:"relayedby" yaml:"relayedby"`
IsRelay bool `json:"isrelay" bson:"isrelay" yaml:"isrelay"`
RelayedNodes []string `json:"relaynodes" yaml:"relayedNodes"`
IngressDNS string `json:"ingressdns" yaml:"ingressdns"`
DNSOn bool `json:"dnson" yaml:"dnson"`
ID uuid.UUID `json:"id" yaml:"id"`
HostID uuid.UUID `json:"hostid" yaml:"hostid"`
Network string `json:"network" yaml:"network"`
NetworkRange net.IPNet `json:"networkrange" yaml:"networkrange"`
NetworkRange6 net.IPNet `json:"networkrange6" yaml:"networkrange6"`
Server string `json:"server" yaml:"server"`
Connected bool `json:"connected" yaml:"connected"`
Address net.IPNet `json:"address" yaml:"address"`
Address6 net.IPNet `json:"address6" yaml:"address6"`
Action string `json:"action" yaml:"action"`
LocalAddress net.IPNet `json:"localaddress" yaml:"localaddress"`
IsEgressGateway bool `json:"isegressgateway" yaml:"isegressgateway"`
EgressGatewayRanges []string `json:"egressgatewayranges" bson:"egressgatewayranges" yaml:"egressgatewayranges"`
IsIngressGateway bool `json:"isingressgateway" yaml:"isingressgateway"`
IsInternetGateway bool `json:"isinternetgateway" yaml:"isinternetgateway"`
IsRelayed bool `json:"isrelayed" bson:"isrelayed" yaml:"isrelayed"`
RelayedBy string `json:"relayedby" bson:"relayedby" yaml:"relayedby"`
IsRelay bool `json:"isrelay" bson:"isrelay" yaml:"isrelay"`
RelayedNodes []string `json:"relaynodes" yaml:"relayedNodes"`
IngressDNS string `json:"ingressdns" yaml:"ingressdns"`
DNSOn bool `json:"dnson" yaml:"dnson"`
}
// Node - a model of a network node

View file

@ -64,11 +64,12 @@ type IngressGwUsers struct {
// UserRemoteGws - struct to hold user's remote gws
type UserRemoteGws struct {
GwID string `json:"remote_access_gw_id"`
GWName string `json:"gw_name"`
Network string `json:"network"`
Connected bool `json:"connected"`
GwClient ExtClient `json:"gw_client"`
GwID string `json:"remote_access_gw_id"`
GWName string `json:"gw_name"`
Network string `json:"network"`
Connected bool `json:"connected"`
IsInternetGateway bool `json:"is_internet_gateway"`
GwClient ExtClient `json:"gw_client"`
}
// UserRemoteGwsReq - struct to hold user remote acccess gws req
@ -189,8 +190,8 @@ type HostRelayRequest struct {
// IngressRequest - ingress request struct
type IngressRequest struct {
ExtclientDNS string `json:"extclientdns"`
Failover bool `json:"failover"`
ExtclientDNS string `json:"extclientdns"`
IsInternetGateway bool `json:"is_internet_gw"`
}
// ServerUpdateData - contains data to configure server

View file

@ -197,11 +197,12 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
gws := userGws[node.Network]
gws = append(gws, models.UserRemoteGws{
GwID: node.ID.String(),
GWName: host.Name,
Network: node.Network,
GwClient: extClient,
Connected: true,
GwID: node.ID.String(),
GWName: host.Name,
Network: node.Network,
GwClient: extClient,
Connected: true,
IsInternetGateway: node.IsInternetGateway,
})
userGws[node.Network] = gws
delete(user.RemoteGwIDs, node.ID.String())
@ -230,9 +231,10 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
gws := userGws[node.Network]
gws = append(gws, models.UserRemoteGws{
GwID: node.ID.String(),
GWName: host.Name,
Network: node.Network,
GwID: node.ID.String(),
GWName: host.Name,
Network: node.Network,
IsInternetGateway: node.IsInternetGateway,
})
userGws[node.Network] = gws
}

View file

@ -61,6 +61,8 @@ func InitPro() {
logic.UpdateRelayed = proLogic.UpdateRelayed
logic.SetRelayedNodes = proLogic.SetRelayedNodes
logic.RelayUpdates = proLogic.RelayUpdates
logic.IsInternetGw = proLogic.IsInternetGw
logic.SetInternetGw = proLogic.SetInternetGw
mq.UpdateMetrics = proLogic.MQUpdateMetrics
}

View file

@ -5,6 +5,16 @@ import (
"github.com/gravitl/netmaker/models"
)
// IsInternetGw - checks if node is acting as internet gw
func IsInternetGw(node models.Node) bool {
return node.IsInternetGateway
}
// SetInternetGw - sets the node as internet gw based on flag bool
func SetInternetGw(node *models.Node, flag bool) {
node.IsInternetGateway = flag
}
// GetNetworkIngresses - gets the gateways of a network
func GetNetworkIngresses(network string) ([]models.Node, error) {
var ingresses []models.Node