diff --git a/changelog.md b/changelog.md index 70085bc1..c4f3f12b 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 7a8dd65d..9a24ecea 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 ed3eb04e..3b1fb04f 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 50ca7a4f..b09b32cf 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 e2c65329..df7c785a 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,54 +145,39 @@ func (p *Publisher) UpdateCNAMES(cnames []string, ttl uint32) error { } p.cnames = cnames + p.published = true return nil } func (p *Publisher) Close() { - p.avahiServer.Close() -} - -var publisher *Publisher -var publisherMu sync.Mutex - -func publishing(ctx context.Context, publisher *Publisher, ttl, interval uint32) error { - resendDuration := time.Duration(interval) * time.Second - ticker := time.NewTicker(resendDuration) - defer ticker.Stop() - - publishFunc := func() error { - publisherMu.Lock() - cnamesToPublish := publisher.cnames - publisherMu.Unlock() - - err := publisher.UpdateCNAMES(cnamesToPublish, ttl) + p.mu.Lock() + defer p.mu.Unlock() + if p.avahiEntryGroup != nil { + err := p.avahiEntryGroup.Reset() if err != nil { - utils.Error("[mDNS] failed to update CNAMEs", err) - } else { - utils.Debug("[mDNS] Successfully published CNAMEs: " + fmt.Sprint(cnamesToPublish)) + utils.Error("[mDNS] failed to reset entry group during close", err) } - return err + p.avahiEntryGroup = nil } - - // Publish immediately - if err := publishFunc(); err != nil { - return err + if p.avahiServer != nil { + p.avahiServer.Close() + } + if p.dbusConn != nil { + p.dbusConn.Close() } + p.published = false +} - for { - select { - case <-ticker.C: - if err := publishFunc(); err != nil { - utils.Error("[mDNS] Failed to publish CNAMEs in ticker", err) - // Continue the loop instead of returning, to keep trying - continue - } - case <-ctx.Done(): - utils.Log("[mDNS] context is done, closing publisher") - publisher.Close() - return nil +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() { @@ -171,18 +194,10 @@ func PublishAllMDNSFromConfig() { 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 { @@ -199,7 +214,6 @@ func PublishAllMDNSFromConfig() { 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 @@ -209,4 +223,59 @@ func PublishAllMDNSFromConfig() { if err != nil { utils.Error("[mDNS] failed to update CNAMEs", err) } -} \ No newline at end of file +} + +func RestartMDNS() { + publisherMu.Lock() + defer publisherMu.Unlock() + + if publisher != nil { + publisher.Close() + publisher = nil + } + + PublishAllMDNSFromConfig() +} + +var publisher *Publisher +var publisherMu sync.Mutex + +func publishing(ctx context.Context, publisher *Publisher, ttl, interval uint32) error { + resendDuration := time.Duration(interval) * time.Second + ticker := time.NewTicker(resendDuration) + defer ticker.Stop() + + publishFunc := func() error { + publisherMu.Lock() + cnamesToPublish := publisher.cnames + publisherMu.Unlock() + + err := publisher.UpdateCNAMES(cnamesToPublish, ttl) + if err != nil { + utils.Error("[mDNS] failed to update CNAMEs", err) + } else { + utils.Debug("[mDNS] Successfully published CNAMEs: " + fmt.Sprint(cnamesToPublish)) + } + return err + } + + // Publish immediately + if err := publishFunc(); err != nil { + return err + } + + for { + select { + case <-ticker.C: + if err := publishFunc(); err != nil { + utils.Error("[mDNS] Failed to publish CNAMEs in ticker", err) + // Continue the loop instead of returning, to keep trying + continue + } + case <-ctx.Done(): + utils.Log("[mDNS] context is done, closing publisher") + publisher.Close() + return nil + } + } +} diff --git a/src/utils/utils.go b/src/utils/utils.go index 720cf6de..96e3cd83 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 {