From fa4fbcd8e5da655b825cf8c45cd770a6bda0ec9f Mon Sep 17 00:00:00 2001 From: Yann Stepienik Date: Tue, 24 Sep 2024 23:44:12 +0100 Subject: [PATCH] [release] v0.16.3-unstable2 --- changelog.md | 5 + client/src/pages/config/routes/routeman.jsx | 4 +- package.json | 2 +- src/dns.go | 14 +- src/proxy/avahi.go | 209 +++++++++++++------- src/utils/utils.go | 7 + 6 files changed, 162 insertions(+), 79 deletions(-) diff --git a/changelog.md b/changelog.md index 70085bc..c4f3f12 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,8 @@ +## Version 0.16.3 + - Local domains now produce services instead of CNAME for better compatibility + - DNS Lookup is now a warning + - DNS Lookup ignores local domains + ## Version 0.16.2 - Only propose cosmos.local as default to setup using local domains diff --git a/client/src/pages/config/routes/routeman.jsx b/client/src/pages/config/routes/routeman.jsx index 7a8dd65..9a24ece 100644 --- a/client/src/pages/config/routes/routeman.jsx +++ b/client/src/pages/config/routes/routeman.jsx @@ -112,8 +112,6 @@ const RouteManagement = ({ routeConfig, routeNames, config, TargetContainer, noC fullValues = sanitizeRoute(fullValues); - console.log(fullValues) - let op; if(newRoute) { op = API.config.newRoute(routeConfig.Name, fullValues) @@ -254,7 +252,7 @@ const RouteManagement = ({ routeConfig, routeNames, config, TargetContainer, noC }} /> {hostError && - {hostError} + {hostError} } )} diff --git a/package.json b/package.json index ed3eb04..3b1fb04 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cosmos-server", - "version": "0.16.3-unstable1", + "version": "0.16.3-unstable2", "description": "", "main": "test-server.js", "bugs": { diff --git a/src/dns.go b/src/dns.go index 50ca7a4..b09b32c 100644 --- a/src/dns.go +++ b/src/dns.go @@ -24,12 +24,16 @@ func CheckDNSRoute(w http.ResponseWriter, req *http.Request) { return } - errDNS := utils.CheckDNS(url) + // if ends with .local + if !strings.HasSuffix(url, ".local") { - if errDNS != nil { - utils.Error("CheckDNS", errDNS) - utils.HTTPError(w, "DNS Check error: " + errDNS.Error(), http.StatusInternalServerError, "DNS002") - return + errDNS := utils.CheckDNS(url) + + if errDNS != nil { + utils.Error("CheckDNS", errDNS) + utils.HTTPError(w, "DNS Check error: " + errDNS.Error(), http.StatusInternalServerError, "DNS002") + return + } } json.NewEncoder(w).Encode(map[string]interface{}{ diff --git a/src/proxy/avahi.go b/src/proxy/avahi.go index e2c6532..df7c785 100644 --- a/src/proxy/avahi.go +++ b/src/proxy/avahi.go @@ -5,6 +5,8 @@ import ( "fmt" "sync" "time" + "net" + "strconv" "github.com/godbus/dbus/v5" "github.com/holoplot/go-avahi" @@ -26,6 +28,7 @@ type Publisher struct { rdataField []byte mu sync.Mutex cnames []string + published bool } func NewPublisher() (*Publisher, error) { @@ -74,30 +77,65 @@ func NewPublisher() (*Publisher, error) { func (p *Publisher) Fqdn() string { return p.fqdn } - func (p *Publisher) UpdateCNAMES(cnames []string, ttl uint32) error { p.mu.Lock() defer p.mu.Unlock() + // If the CNAMEs haven't changed and we've already published, do nothing + if p.published && stringSlicesEqual(p.cnames, cnames) { + return nil + } + if err := p.avahiEntryGroup.Reset(); err != nil { utils.Error("[mDNS] failed to reset entry group", err) return err } - for _, cname := range cnames { - err := p.avahiEntryGroup.AddRecord( - avahi.InterfaceUnspec, - avahi.ProtoUnspec, - uint32(0), - cname, - AVAHI_DNS_CLASS_IN, - AVAHI_DNS_TYPE_CNAME, - ttl, - p.rdataField, - ) - if err != nil { - utils.Error("[mDNS] failed to add record to entry group", err) - return err + ifaces, err := net.Interfaces() + if err != nil { + utils.Error("[mDNS] failed to get network interfaces", err) + return err + } + + for _, iface := range ifaces { + if iface.Flags&net.FlagLoopback != 0 { + continue + } + + portStr, _ := strconv.Atoi(utils.GetServerPort()) + + for _, cname := range cnames { + utils.Log(fmt.Sprintf("[mDNS] Adding service for: %s on interface %s", cname, iface.Name)) + err := p.avahiEntryGroup.AddService( + int32(iface.Index), + avahi.ProtoUnspec, + 0, + cname, + "_http._tcp", + "", + "", + uint16(portStr), + nil, + ) + if err != nil { + utils.Error(fmt.Sprintf("[mDNS] failed to add service to entry group for interface %s", iface.Name), err) + continue + } + + err = p.avahiEntryGroup.AddRecord( + int32(iface.Index), + avahi.ProtoUnspec, + 0, + cname, + AVAHI_DNS_CLASS_IN, + AVAHI_DNS_TYPE_CNAME, + ttl, + p.rdataField, + ) + if err != nil { + utils.Error(fmt.Sprintf("[mDNS] failed to add CNAME record to entry group for interface %s", iface.Name), err) + continue + } } } @@ -107,11 +145,96 @@ func (p *Publisher) UpdateCNAMES(cnames []string, ttl uint32) error { } p.cnames = cnames + p.published = true return nil } func (p *Publisher) Close() { - p.avahiServer.Close() + p.mu.Lock() + defer p.mu.Unlock() + if p.avahiEntryGroup != nil { + err := p.avahiEntryGroup.Reset() + if err != nil { + utils.Error("[mDNS] failed to reset entry group during close", err) + } + p.avahiEntryGroup = nil + } + if p.avahiServer != nil { + p.avahiServer.Close() + } + if p.dbusConn != nil { + p.dbusConn.Close() + } + p.published = false +} + +func stringSlicesEqual(a, b []string) bool { + if len(a) != len(b) { + return false + } + for i, v := range a { + if v != b[i] { + return false + } + } + return true +} + +func PublishAllMDNSFromConfig() { + config := utils.GetMainConfig() + utils.Log("[mDNS] Publishing routes to mDNS") + + publisherMu.Lock() + defer publisherMu.Unlock() + + var err error + if publisher == nil { + publisher, err = NewPublisher() + if err != nil { + utils.Error("[mDNS] failed to start mDNS (*.local domains). Install Avahi to solve this issue.", err) + return + } + } + + routes := utils.GetAllHostnames(false, true) + + localRoutes := []string{} + + if config.NewInstall { + localRoutes = []string{ + "setup-cosmos.local", + } + } else { + for _, route := range routes { + if len(route) > 6 && route[len(route)-6:] == ".local" { + localRoutes = append(localRoutes, route) + } + } + } + + utils.Log("[mDNS] Publishing the following routes to mDNS: " + fmt.Sprint(localRoutes)) + + if len(localRoutes) == 0 { + utils.Log("[mDNS] No .local domains to publish") + return + } + + err = publisher.UpdateCNAMES(localRoutes, 60) + if err != nil { + utils.Error("[mDNS] failed to update CNAMEs", err) + } +} + +func RestartMDNS() { + publisherMu.Lock() + defer publisherMu.Unlock() + + if publisher != nil { + publisher.Close() + publisher = nil + } + + PublishAllMDNSFromConfig() } var publisher *Publisher @@ -156,57 +279,3 @@ func publishing(ctx context.Context, publisher *Publisher, ttl, interval uint32) } } } - -func PublishAllMDNSFromConfig() { - config := utils.GetMainConfig() - utils.Log("[mDNS] Publishing routes to mDNS") - - publisherMu.Lock() - defer publisherMu.Unlock() - - var err error - if publisher == nil { - publisher, err = NewPublisher() - if err != nil { - utils.Error("[mDNS] failed to start mDNS (*.local domains). Install Avahi to solve this issue.", err) - return - } - - go func() { - err := publishing(context.Background(), publisher, 60, 5) - if err != nil { - utils.Error("[mDNS] mDNS publishing loop failed", err) - } - }() - } - - routes := utils.GetAllHostnames(false, true) - - // only keep .local domains - localRoutes := []string{} - - if config.NewInstall { - localRoutes = []string{ - "setup-cosmos.local", - } - } else { - for _, route := range routes { - if len(route) > 6 && route[len(route)-6:] == ".local" { - localRoutes = append(localRoutes, route) - } - } - } - - utils.Log("[mDNS] Publishing the following routes to mDNS: " + fmt.Sprint(localRoutes)) - - // if empty - if len(localRoutes) == 0 { - utils.Log("[mDNS] No .local domains to publish") - return - } - - err = publisher.UpdateCNAMES(localRoutes, 60) - if err != nil { - utils.Error("[mDNS] failed to update CNAMEs", err) - } -} \ No newline at end of file diff --git a/src/utils/utils.go b/src/utils/utils.go index 720cf6d..96e3cd8 100644 --- a/src/utils/utils.go +++ b/src/utils/utils.go @@ -643,6 +643,13 @@ func GetServerURL(overwriteHostname string) string { return ServerURL + "/" } +func GetServerPort() string { + if IsHTTPS { + return MainConfig.HTTPConfig.HTTPSPort + } + return MainConfig.HTTPConfig.HTTPPort +} + func ImageToBase64(path string) (string, error) { imageFile, err := os.Open(path) if err != nil {