Explorar el Código

add support for egress domain routing

abhishek9686 hace 1 mes
padre
commit
626f725d7c
Se han modificado 6 ficheros con 69 adiciones y 5 borrados
  1. 35 4
      controllers/egress.go
  2. 13 1
      controllers/hosts.go
  3. 15 0
      logic/util.go
  4. 2 0
      models/egress.go
  5. 3 0
      models/host.go
  6. 1 0
      schema/egress.go

+ 35 - 4
controllers/egress.go

@@ -46,13 +46,22 @@ func createEgress(w http.ResponseWriter, r *http.Request) {
 	}
 	var egressRange string
 	if !req.IsInetGw {
-		egressRange, err = logic.NormalizeCIDR(req.Range)
-		if err != nil {
-			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
-			return
+		if req.Domain != "" {
+			if !logic.IsFQDN(req.Domain) {
+				logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("bad domain name"), "badrequest"))
+				return
+			}
+		} else {
+			egressRange, err = logic.NormalizeCIDR(req.Range)
+			if err != nil {
+				logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+				return
+			}
 		}
+
 	} else {
 		egressRange = "*"
+		req.Domain = ""
 	}
 
 	e := schema.Egress{
@@ -61,6 +70,7 @@ func createEgress(w http.ResponseWriter, r *http.Request) {
 		Network:     req.Network,
 		Description: req.Description,
 		Range:       egressRange,
+		Domain:      req.Domain,
 		Nat:         req.Nat,
 		Nodes:       make(datatypes.JSONMap),
 		Tags:        make(datatypes.JSONMap),
@@ -108,6 +118,27 @@ func createEgress(w http.ResponseWriter, r *http.Request) {
 	// 	}
 
 	// }
+	if req.Domain != "" {
+		if req.Nodes != nil {
+			for nodeID := range req.Nodes {
+				node, err := logic.GetNodeByID(nodeID)
+				if err == nil {
+					continue
+				}
+				host := logic.GetHostByNodeID(nodeID)
+				if host == nil {
+					continue
+				}
+				mq.HostUpdate(&models.HostUpdate{
+					Action:   models.EgressUpdate,
+					Host:     *host,
+					EgressID: e.ID,
+					Node:     node,
+				})
+			}
+		}
+
+	}
 	go mq.PublishPeerUpdate(false)
 	logic.ReturnSuccessResponseWithJson(w, r, e, "created egress resource")
 }

+ 13 - 1
controllers/hosts.go

@@ -5,6 +5,7 @@ import (
 	"errors"
 	"fmt"
 	"net/http"
+	"strings"
 	"time"
 
 	"github.com/google/uuid"
@@ -383,12 +384,23 @@ func hostUpdateFallback(w http.ResponseWriter, r *http.Request) {
 		err := logic.UpsertHost(currentHost)
 		if err != nil {
 			slog.Error("failed to update host", "id", currentHost.ID, "error", err)
-			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+			logic.ReturnErrorResponse(w, r, logic.FormatError(err, logic.Internal))
 			return
 		}
 
 	case models.UpdateMetrics:
 		mq.UpdateMetricsFallBack(hostUpdate.Node.ID.String(), hostUpdate.NewMetrics)
+	case models.EgressUpdate:
+		e := schema.Egress{ID: hostUpdate.EgressID}
+		err = e.Get(db.WithContext(r.Context()))
+		if err != nil {
+			logic.ReturnErrorResponse(w, r, logic.FormatError(err, logic.BadReq))
+			return
+		}
+		if len(hostUpdate.Node.EgressGatewayRanges) > 0 {
+			e.Range = strings.Join(hostUpdate.Node.EgressGatewayRanges, ",")
+			e.Update(db.WithContext(r.Context()))
+		}
 	}
 
 	if sendPeerUpdate {

+ 15 - 0
logic/util.go

@@ -12,6 +12,7 @@ import (
 	"net/http"
 	"os"
 	"reflect"
+	"regexp"
 	"strings"
 	"time"
 	"unicode"
@@ -273,3 +274,17 @@ func compareIface(a, b models.Iface) bool {
 		a.Address.Mask.String() == b.Address.Mask.String() &&
 		a.AddressString == b.AddressString
 }
+
+// IsFQDN checks if the given string is a valid Fully Qualified Domain Name (FQDN)
+func IsFQDN(domain string) bool {
+	// Basic check to ensure the domain is not empty and has at least one dot (.)
+	if domain == "" || !strings.Contains(domain, ".") {
+		return false
+	}
+
+	// Regular expression for validating FQDN (basic check for valid characters and structure)
+	fqdnRegex := `^(?i)([a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$`
+	re := regexp.MustCompile(fqdnRegex)
+
+	return re.MatchString(domain)
+}

+ 2 - 0
models/egress.go

@@ -8,7 +8,9 @@ type EgressReq struct {
 	Nodes       map[string]int `json:"nodes"`
 	Tags        []string       `json:"tags"`
 	Range       string         `json:"range"`
+	Domain      string         `json:"domain"`
 	Nat         bool           `json:"nat"`
 	Status      bool           `json:"status"`
 	IsInetGw    bool           `json:"is_internet_gateway"`
+	Dns         string         `json:"dns"`
 }

+ 3 - 0
models/host.go

@@ -124,6 +124,8 @@ const (
 	SignalPull HostMqAction = "SIGNAL_PULL"
 	// UpdateMetrics - updates metrics data
 	UpdateMetrics HostMqAction = "UPDATE_METRICS"
+	// EgressUpdate - const for egress update action
+	EgressUpdate HostMqAction = "EGRESS_UPDATE"
 )
 
 // SignalAction - turn peer signal action
@@ -142,6 +144,7 @@ type HostUpdate struct {
 	Host       Host
 	Node       Node
 	Signal     Signal
+	EgressID   string
 	NewMetrics Metrics
 }
 

+ 1 - 0
schema/egress.go

@@ -18,6 +18,7 @@ type Egress struct {
 	Nodes       datatypes.JSONMap `gorm:"nodes" json:"nodes"`
 	Tags        datatypes.JSONMap `gorm:"tags" json:"tags"`
 	Range       string            `gorm:"range" json:"range"`
+	Domain      string            `gorm:"domain" json:"domain"`
 	Nat         bool              `gorm:"nat" json:"nat"`
 	//IsInetGw    bool              `gorm:"is_inet_gw" json:"is_internet_gateway"`
 	Status    bool      `gorm:"status" json:"status"`