mirror of
https://github.com/gravitl/netmaker.git
synced 2025-11-03 11:02:11 +08:00
feat(NET-1106): support additional RAG endpoint IPs (#2907)
This commit is contained in:
@@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
"github.com/gravitl/netmaker/mq"
|
"github.com/gravitl/netmaker/mq"
|
||||||
"github.com/skip2/go-qrcode"
|
"github.com/skip2/go-qrcode"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
"golang.org/x/exp/slog"
|
"golang.org/x/exp/slog"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
)
|
)
|
||||||
@@ -199,6 +200,24 @@ func getExtClientConf(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preferredIp := strings.TrimSpace(r.URL.Query().Get("preferredip"))
|
||||||
|
if preferredIp != "" {
|
||||||
|
allowedPreferredIps := []string{}
|
||||||
|
for i := range gwnode.AdditionalRagIps {
|
||||||
|
allowedPreferredIps = append(allowedPreferredIps, gwnode.AdditionalRagIps[i].String())
|
||||||
|
}
|
||||||
|
allowedPreferredIps = append(allowedPreferredIps, host.EndpointIP.String())
|
||||||
|
allowedPreferredIps = append(allowedPreferredIps, host.EndpointIPv6.String())
|
||||||
|
if !slices.Contains(allowedPreferredIps, preferredIp) {
|
||||||
|
slog.Warn("preferred endpoint ip is not associated with the RAG. proceeding with preferred ip", "preferred ip", preferredIp)
|
||||||
|
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("preferred endpoint ip is not associated with the RAG"), "badrequest"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if net.ParseIP(preferredIp).To4() == nil {
|
||||||
|
preferredIp = fmt.Sprintf("[%s]", preferredIp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
addrString := client.Address
|
addrString := client.Address
|
||||||
if addrString != "" {
|
if addrString != "" {
|
||||||
addrString += "/32"
|
addrString += "/32"
|
||||||
@@ -214,12 +233,18 @@ func getExtClientConf(w http.ResponseWriter, r *http.Request) {
|
|||||||
if network.DefaultKeepalive != 0 {
|
if network.DefaultKeepalive != 0 {
|
||||||
keepalive = "PersistentKeepalive = " + strconv.Itoa(int(network.DefaultKeepalive))
|
keepalive = "PersistentKeepalive = " + strconv.Itoa(int(network.DefaultKeepalive))
|
||||||
}
|
}
|
||||||
|
|
||||||
gwendpoint := ""
|
gwendpoint := ""
|
||||||
if host.EndpointIP.To4() == nil {
|
if preferredIp == "" {
|
||||||
gwendpoint = fmt.Sprintf("[%s]:%d", host.EndpointIP.String(), host.ListenPort)
|
if host.EndpointIP.To4() == nil {
|
||||||
|
gwendpoint = fmt.Sprintf("[%s]:%d", host.EndpointIPv6.String(), host.ListenPort)
|
||||||
|
} else {
|
||||||
|
gwendpoint = fmt.Sprintf("%s:%d", host.EndpointIP.String(), host.ListenPort)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
gwendpoint = fmt.Sprintf("%s:%d", host.EndpointIP.String(), host.ListenPort)
|
gwendpoint = fmt.Sprintf("%s:%d", preferredIp, host.ListenPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
var newAllowedIPs string
|
var newAllowedIPs string
|
||||||
if logic.IsInternetGw(gwnode) || gwnode.InternetGwID != "" {
|
if logic.IsInternetGw(gwnode) || gwnode.InternetGwID != "" {
|
||||||
egressrange := "0.0.0.0/0"
|
egressrange := "0.0.0.0/0"
|
||||||
|
|||||||
@@ -635,14 +635,20 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
|
|||||||
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("metadata cannot be longer than 255 characters"), "badrequest"))
|
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("metadata cannot be longer than 255 characters"), "badrequest"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if !servercfg.IsPro {
|
||||||
|
newData.AdditionalRagIps = []string{}
|
||||||
|
}
|
||||||
newNode := newData.ConvertToServerNode(¤tNode)
|
newNode := newData.ConvertToServerNode(¤tNode)
|
||||||
|
if newNode == nil {
|
||||||
|
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("error converting node"), "badrequest"))
|
||||||
|
return
|
||||||
|
}
|
||||||
if newNode.IsInternetGateway != currentNode.IsInternetGateway {
|
if newNode.IsInternetGateway != currentNode.IsInternetGateway {
|
||||||
if newNode.IsInternetGateway {
|
if newNode.IsInternetGateway {
|
||||||
logic.SetInternetGw(newNode, models.InetNodeReq{})
|
logic.SetInternetGw(newNode, models.InetNodeReq{})
|
||||||
} else {
|
} else {
|
||||||
logic.UnsetInternetGw(newNode)
|
logic.UnsetInternetGw(newNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
relayUpdate := logic.RelayUpdates(¤tNode, newNode)
|
relayUpdate := logic.RelayUpdates(¤tNode, newNode)
|
||||||
if relayUpdate && newNode.IsRelay {
|
if relayUpdate && newNode.IsRelay {
|
||||||
|
|||||||
@@ -44,7 +44,13 @@ func (h *Host) ConvertNMHostToAPI() *ApiHost {
|
|||||||
a := ApiHost{}
|
a := ApiHost{}
|
||||||
a.Debug = h.Debug
|
a.Debug = h.Debug
|
||||||
a.EndpointIP = h.EndpointIP.String()
|
a.EndpointIP = h.EndpointIP.String()
|
||||||
|
if a.EndpointIP == "<nil>" {
|
||||||
|
a.EndpointIP = ""
|
||||||
|
}
|
||||||
a.EndpointIPv6 = h.EndpointIPv6.String()
|
a.EndpointIPv6 = h.EndpointIPv6.String()
|
||||||
|
if a.EndpointIPv6 == "<nil>" {
|
||||||
|
a.EndpointIPv6 = ""
|
||||||
|
}
|
||||||
a.FirewallInUse = h.FirewallInUse
|
a.FirewallInUse = h.FirewallInUse
|
||||||
a.ID = h.ID.String()
|
a.ID = h.ID.String()
|
||||||
a.Interfaces = make([]ApiIface, len(h.Interfaces))
|
a.Interfaces = make([]ApiIface, len(h.Interfaces))
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"golang.org/x/exp/slog"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ApiNode is a stripped down Node DTO that exposes only required fields to external systems
|
// ApiNode is a stripped down Node DTO that exposes only required fields to external systems
|
||||||
@@ -44,6 +45,7 @@ type ApiNode struct {
|
|||||||
IsInternetGateway bool `json:"isinternetgateway" yaml:"isinternetgateway"`
|
IsInternetGateway bool `json:"isinternetgateway" yaml:"isinternetgateway"`
|
||||||
InetNodeReq InetNodeReq `json:"inet_node_req" yaml:"inet_node_req"`
|
InetNodeReq InetNodeReq `json:"inet_node_req" yaml:"inet_node_req"`
|
||||||
InternetGwID string `json:"internetgw_node_id" yaml:"internetgw_node_id"`
|
InternetGwID string `json:"internetgw_node_id" yaml:"internetgw_node_id"`
|
||||||
|
AdditionalRagIps []string `json:"additional_rag_ips" yaml:"additional_rag_ips"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApiNode.ConvertToServerNode - converts an api node to a server node
|
// ApiNode.ConvertToServerNode - converts an api node to a server node
|
||||||
@@ -109,6 +111,14 @@ func (a *ApiNode) ConvertToServerNode(currentNode *Node) *Node {
|
|||||||
convertedNode.LastPeerUpdate = time.Unix(a.LastPeerUpdate, 0)
|
convertedNode.LastPeerUpdate = time.Unix(a.LastPeerUpdate, 0)
|
||||||
convertedNode.ExpirationDateTime = time.Unix(a.ExpirationDateTime, 0)
|
convertedNode.ExpirationDateTime = time.Unix(a.ExpirationDateTime, 0)
|
||||||
convertedNode.Metadata = a.Metadata
|
convertedNode.Metadata = a.Metadata
|
||||||
|
for _, ip := range a.AdditionalRagIps {
|
||||||
|
ragIp := net.ParseIP(ip)
|
||||||
|
if ragIp == nil {
|
||||||
|
slog.Error("error parsing additional rag ip", "error", err, "ip", ip)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
convertedNode.AdditionalRagIps = append(convertedNode.AdditionalRagIps, ragIp)
|
||||||
|
}
|
||||||
return &convertedNode
|
return &convertedNode
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,6 +173,10 @@ func (nm *Node) ConvertToAPINode() *ApiNode {
|
|||||||
apiNode.FailOverPeers = nm.FailOverPeers
|
apiNode.FailOverPeers = nm.FailOverPeers
|
||||||
apiNode.FailedOverBy = nm.FailedOverBy
|
apiNode.FailedOverBy = nm.FailedOverBy
|
||||||
apiNode.Metadata = nm.Metadata
|
apiNode.Metadata = nm.Metadata
|
||||||
|
apiNode.AdditionalRagIps = []string{}
|
||||||
|
for _, ip := range nm.AdditionalRagIps {
|
||||||
|
apiNode.AdditionalRagIps = append(apiNode.AdditionalRagIps, ip.String())
|
||||||
|
}
|
||||||
return &apiNode
|
return &apiNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ type Node struct {
|
|||||||
IsInternetGateway bool `json:"isinternetgateway" yaml:"isinternetgateway"`
|
IsInternetGateway bool `json:"isinternetgateway" yaml:"isinternetgateway"`
|
||||||
InetNodeReq InetNodeReq `json:"inet_node_req" yaml:"inet_node_req"`
|
InetNodeReq InetNodeReq `json:"inet_node_req" yaml:"inet_node_req"`
|
||||||
InternetGwID string `json:"internetgw_node_id" yaml:"internetgw_node_id"`
|
InternetGwID string `json:"internetgw_node_id" yaml:"internetgw_node_id"`
|
||||||
|
AdditionalRagIps []net.IP `json:"additional_rag_ips" yaml:"additional_rag_ips"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// LegacyNode - legacy struct for node model
|
// LegacyNode - legacy struct for node model
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ type UserRemoteGws struct {
|
|||||||
GwClient ExtClient `json:"gw_client"`
|
GwClient ExtClient `json:"gw_client"`
|
||||||
GwPeerPublicKey string `json:"gw_peer_public_key"`
|
GwPeerPublicKey string `json:"gw_peer_public_key"`
|
||||||
Metadata string `json:"metadata"`
|
Metadata string `json:"metadata"`
|
||||||
|
AllowedEndpoints []string `json:"allowed_endpoints"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserRemoteGwsReq - struct to hold user remote acccess gws req
|
// UserRemoteGwsReq - struct to hold user remote acccess gws req
|
||||||
@@ -372,3 +373,7 @@ type LoginReqDto struct {
|
|||||||
const (
|
const (
|
||||||
ResHeaderKeyStAccessToken = "St-Access-Token"
|
ResHeaderKeyStAccessToken = "St-Access-Token"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type GetClientConfReqDto struct {
|
||||||
|
PreferredIp string `json:"preferred_ip"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -227,6 +227,7 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
|
|||||||
IsInternetGateway: node.IsInternetGateway,
|
IsInternetGateway: node.IsInternetGateway,
|
||||||
GwPeerPublicKey: host.PublicKey.String(),
|
GwPeerPublicKey: host.PublicKey.String(),
|
||||||
Metadata: node.Metadata,
|
Metadata: node.Metadata,
|
||||||
|
AllowedEndpoints: getAllowedRagEndpoints(&node, host),
|
||||||
})
|
})
|
||||||
userGws[node.Network] = gws
|
userGws[node.Network] = gws
|
||||||
delete(user.RemoteGwIDs, node.ID.String())
|
delete(user.RemoteGwIDs, node.ID.String())
|
||||||
@@ -242,6 +243,7 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
|
|||||||
IsInternetGateway: node.IsInternetGateway,
|
IsInternetGateway: node.IsInternetGateway,
|
||||||
GwPeerPublicKey: host.PublicKey.String(),
|
GwPeerPublicKey: host.PublicKey.String(),
|
||||||
Metadata: node.Metadata,
|
Metadata: node.Metadata,
|
||||||
|
AllowedEndpoints: getAllowedRagEndpoints(&node, host),
|
||||||
})
|
})
|
||||||
userGws[node.Network] = gws
|
userGws[node.Network] = gws
|
||||||
processedAdminNodeIds[node.ID.String()] = struct{}{}
|
processedAdminNodeIds[node.ID.String()] = struct{}{}
|
||||||
@@ -275,6 +277,7 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
|
|||||||
IsInternetGateway: node.IsInternetGateway,
|
IsInternetGateway: node.IsInternetGateway,
|
||||||
GwPeerPublicKey: host.PublicKey.String(),
|
GwPeerPublicKey: host.PublicKey.String(),
|
||||||
Metadata: node.Metadata,
|
Metadata: node.Metadata,
|
||||||
|
AllowedEndpoints: getAllowedRagEndpoints(&node, host),
|
||||||
})
|
})
|
||||||
userGws[node.Network] = gws
|
userGws[node.Network] = gws
|
||||||
}
|
}
|
||||||
@@ -302,6 +305,7 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
|
|||||||
IsInternetGateway: node.IsInternetGateway,
|
IsInternetGateway: node.IsInternetGateway,
|
||||||
GwPeerPublicKey: host.PublicKey.String(),
|
GwPeerPublicKey: host.PublicKey.String(),
|
||||||
Metadata: node.Metadata,
|
Metadata: node.Metadata,
|
||||||
|
AllowedEndpoints: getAllowedRagEndpoints(&node, host),
|
||||||
})
|
})
|
||||||
userGws[node.Network] = gws
|
userGws[node.Network] = gws
|
||||||
}
|
}
|
||||||
@@ -352,3 +356,19 @@ func ingressGatewayUsers(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
json.NewEncoder(w).Encode(gwUsers)
|
json.NewEncoder(w).Encode(gwUsers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getAllowedRagEndpoints(ragNode *models.Node, ragHost *models.Host) []string {
|
||||||
|
endpoints := []string{}
|
||||||
|
if len(ragHost.EndpointIP) > 0 {
|
||||||
|
endpoints = append(endpoints, ragHost.EndpointIP.String())
|
||||||
|
}
|
||||||
|
if len(ragHost.EndpointIPv6) > 0 {
|
||||||
|
endpoints = append(endpoints, ragHost.EndpointIPv6.String())
|
||||||
|
}
|
||||||
|
if servercfg.IsPro {
|
||||||
|
for _, ip := range ragNode.AdditionalRagIps {
|
||||||
|
endpoints = append(endpoints, ip.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return endpoints
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user