package dns import ( "net" "strings" "time" "github.com/hashicorp/golang-lru/v2" ) type lookupCacheEntry struct { cachedName string timestamp time.Time } var lookupCacheValidity = 30 * time.Second var lookupCache *lru.Cache[string, lookupCacheEntry] var defaultPagesRepo = "pages" // GetTargetFromDNS searches for CNAME or TXT entries on the request domain ending with MainDomainSuffix. // If everything is fine, it returns the target data. func GetTargetFromDNS(domain, mainDomainSuffix, firstDefaultBranch string) (targetOwner, targetRepo, targetBranch string) { // Get CNAME or TXT var cname string var err error if lookupCache == nil { lookupCache, err = lru.New[string, lookupCacheEntry](4096) if err != nil { panic(err) // This should only happen if 4096 < 0 at the time of writing, which should be reason enough to panic. } } if entry, ok := lookupCache.Get(domain); ok && time.Now().Before(entry.timestamp.Add(lookupCacheValidity)) { cname = entry.cachedName } else { cname, err = net.LookupCNAME(domain) cname = strings.TrimSuffix(cname, ".") if err != nil || !strings.HasSuffix(cname, mainDomainSuffix) { cname = "" // TODO: check if the A record matches! names, err := net.LookupTXT(domain) if err == nil { for _, name := range names { name = strings.TrimSuffix(strings.TrimSpace(name), ".") if strings.HasSuffix(name, mainDomainSuffix) { cname = name break } } } } _ = lookupCache.Add(domain, lookupCacheEntry{ cname, time.Now(), }) } if cname == "" { return } cnameParts := strings.Split(strings.TrimSuffix(cname, mainDomainSuffix), ".") targetOwner = cnameParts[len(cnameParts)-1] if len(cnameParts) > 1 { targetRepo = cnameParts[len(cnameParts)-2] } if len(cnameParts) > 2 { targetBranch = cnameParts[len(cnameParts)-3] } if targetRepo == "" { targetRepo = defaultPagesRepo } if targetBranch == "" && targetRepo != defaultPagesRepo { targetBranch = firstDefaultBranch } // if targetBranch is still empty, the caller must find the default branch return }