From 7460d164e080f34efcb68c208158866583d2a498 Mon Sep 17 00:00:00 2001 From: Thomas Limoncelli Date: Thu, 4 Dec 2025 15:46:29 -0500 Subject: [PATCH] CF_SINGLE_REDIRECT fixes --- .../domain-modifiers/CF_REDIRECT.md | 6 ++--- .../domain-modifiers/CF_SINGLE_REDIRECT.md | 24 ++++++++++++++----- .../domain-modifiers/CF_TEMP_REDIRECT.md | 11 +++++---- providers/cloudflare/rest.go | 2 +- .../rtypes/cfsingleredirect/cfredirect.go | 24 ++----------------- 5 files changed, 31 insertions(+), 36 deletions(-) diff --git a/documentation/language-reference/domain-modifiers/CF_REDIRECT.md b/documentation/language-reference/domain-modifiers/CF_REDIRECT.md index b57e1aedd..c355ad804 100644 --- a/documentation/language-reference/domain-modifiers/CF_REDIRECT.md +++ b/documentation/language-reference/domain-modifiers/CF_REDIRECT.md @@ -12,14 +12,14 @@ parameter_types: --- {% hint style="warning" %} -WARNING: Cloudflare is removing this feature and replacing it with a new +**WARNING:** Cloudflare is removing this feature and replacing it with a new feature called "Dynamic Single Redirect". DNSControl will automatically generate "Dynamic Single Redirects" for a limited number of use cases. See [`CLOUDFLAREAPI`](../../provider/cloudflareapi.md) for details. {% endhint %} -`CF_REDIRECT` uses Cloudflare-specific features ("Forwarding URL" Page Rules) to -generate a HTTP 301 permanent redirect. +`CF_REDIRECT` uses Cloudflare-specific features ("Forwarding URL" Page +Rules) to generate a HTTP 301 permanent redirect. If _any_ `CF_REDIRECT` or [`CF_TEMP_REDIRECT`](CF_TEMP_REDIRECT.md) functions are used then `dnscontrol` will manage _all_ "Forwarding URL" type Page Rules for the domain. diff --git a/documentation/language-reference/domain-modifiers/CF_SINGLE_REDIRECT.md b/documentation/language-reference/domain-modifiers/CF_SINGLE_REDIRECT.md index c4fda916c..09d395f11 100644 --- a/documentation/language-reference/domain-modifiers/CF_SINGLE_REDIRECT.md +++ b/documentation/language-reference/domain-modifiers/CF_SINGLE_REDIRECT.md @@ -16,30 +16,42 @@ parameter_types: --- `CF_SINGLE_REDIRECT` is a Cloudflare-specific feature for creating HTTP redirects. 301, 302, 303, 307, 308 are supported. -Typically one uses 302 (temporary) or (less likely) 301 (permanent). +Typically one uses 302 (temporary) or 301 (permanent). This feature manages dynamic "Single Redirects". (Single Redirects can be static or dynamic but DNSControl only maintains dynamic redirects). +DNSControl will delete any "single redirects" it doesn't recognize (i.e. ones created via the web UI) so please be careful. + Cloudflare documentation: {% code title="dnsconfig.js" %} ```javascript D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - CF_SINGLE_REDIRECT("name", 302, "when", "then"), CF_SINGLE_REDIRECT('redirect www.example.com', 302, 'http.host eq "www.example.com"', 'concat("https://otherplace.com", http.request.uri.path)'), CF_SINGLE_REDIRECT('redirect yyy.example.com', 302, 'http.host eq "yyy.example.com"', 'concat("https://survey.stackoverflow.co", "")'), + CF_TEMP_REDIRECT("*example.com/*", "https://contests.otherexample.com/$2"), ); ``` {% endcode %} The fields are: -* name: The name (basically a comment, but it must be unique) +* name: The name (basically a comment) * code: Any of 301, 302, 303, 307, 308. May be a number or string. * when: What Cloudflare sometimes calls the "rule expression". * then: The replacement expression. -{% hint style="info" %} -**NOTE**: The features [`CF_REDIRECT`](CF_REDIRECT.md) and [`CF_TEMP_REDIRECT`](CF_TEMP_REDIRECT.md) generate `CF_SINGLE_REDIRECT` if enabled in [`CLOUDFLAREAPI`](../../provider/cloudflareapi.md). -{% endhint %} +DNSControl does not currently choose the order of the rules. New rules are +added to the end of the list. Use Cloudflare's dashboard to re-order the rule, +DNSControl should not change them. (In the future we hope to add a feature +where the order the rules appear in dnsconfig.js is maintained in the +dashboard.) + +## `CF_REDIRECT` and `CF_TEMP_REDIRECT` + +`CF_REDIRECT` and `CF_TEMP_REDIRECT` used to manage Cloudflare Page Rules. +However that feature is going away. To help with the migration, DNSControl now +translates those commands into CF_SINGLE_REDIRECT equivalents. The conversion +process is a transpiler that only understands certain formats. Please submit +a Github issue if you find something it can't handle. diff --git a/documentation/language-reference/domain-modifiers/CF_TEMP_REDIRECT.md b/documentation/language-reference/domain-modifiers/CF_TEMP_REDIRECT.md index 5840f7ad9..47c65b3ba 100644 --- a/documentation/language-reference/domain-modifiers/CF_TEMP_REDIRECT.md +++ b/documentation/language-reference/domain-modifiers/CF_TEMP_REDIRECT.md @@ -12,7 +12,7 @@ parameter_types: --- {% hint style="warning" %} -**WARNING**: Cloudflare is removing this feature and replacing it with a new +**WARNING:** Cloudflare is removing this feature and replacing it with a new feature called "Dynamic Single Redirect". DNSControl will automatically generate "Dynamic Single Redirects" for a limited number of use cases. See [`CLOUDFLAREAPI`](../../provider/cloudflareapi.md) for details. @@ -21,9 +21,9 @@ generate "Dynamic Single Redirects" for a limited number of use cases. See `CF_TEMP_REDIRECT` uses Cloudflare-specific features ("Forwarding URL" Page Rules) to generate a HTTP 302 temporary redirect. -If _any_ [`CF_REDIRECT`](CF_REDIRECT.md) or `CF_TEMP_REDIRECT` functions are used then +If _any_ [`CF_REDIRECT`](CF_REDIRECT.md) or `CF_TEMP_REDIRECT functions are used then `dnscontrol` will manage _all_ "Forwarding URL" type Page Rules for the domain. -Page Rule types other than "Forwarding URL” will be left alone. +Page Rule types other than "Forwarding URL" will be left alone. {% hint style="warning" %} **WARNING**: Cloudflare does not currently fully document the Page Rules API and @@ -33,10 +33,13 @@ backups and manually verifying `dnscontrol preview` output before running managed by DNSControl and those that aren't. {% endhint %} +This example redirects the bare (aka apex, or naked) domain to www: + {% code title="dnsconfig.js" %} ```javascript D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - CF_TEMP_REDIRECT("example.example.com/*", "https://otherplace.yourdomain.com/$1"), + CF_TEMP_REDIRECT("example.com/*", "https://www.example.com/$1"), + ); ``` {% endcode %} diff --git a/providers/cloudflare/rest.go b/providers/cloudflare/rest.go index bb6cbd1b1..389ae3038 100644 --- a/providers/cloudflare/rest.go +++ b/providers/cloudflare/rest.go @@ -379,7 +379,7 @@ func (c *cloudflareProvider) createSingleRedirect(domainID string, cfr cfsingler return fmt.Errorf("failed fetching redirect rule list cloudflare: %w", err) } newSingleRedirect.Rules = newSingleRedirectRules - newSingleRedirect.Rules = append(newSingleRedirect.Rules, rules.Rules...) + newSingleRedirect.Rules = append(rules.Rules, newSingleRedirect.Rules...) _, err = c.cfClient.UpdateEntrypointRuleset(context.Background(), cloudflare.ZoneIdentifier(domainID), newSingleRedirect) diff --git a/providers/cloudflare/rtypes/cfsingleredirect/cfredirect.go b/providers/cloudflare/rtypes/cfsingleredirect/cfredirect.go index 779600804..be95cc5ff 100644 --- a/providers/cloudflare/rtypes/cfsingleredirect/cfredirect.go +++ b/providers/cloudflare/rtypes/cfsingleredirect/cfredirect.go @@ -2,7 +2,6 @@ package cfsingleredirect import ( "fmt" - "sync" "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/domaintags" @@ -67,9 +66,8 @@ func FromArgs_helper(dcn *domaintags.DomainNameVarieties, rec *models.RecordConf return err } - // Create the old-school name with a count prefix. - incRedirCount(dcn.UniqueName) - name := fmt.Sprintf("%03d,%03d,%s,%s", getRedirCount(dcn.UniqueName), code, prWhen, prThen) + // Create a rule name: + name := fmt.Sprintf("%03d,%s,%s", code, prWhen, prThen) sr := SingleRedirectConfig{} rec.Type = sr.Name() // This record is now a CLOUDFLAREAPI_SINGLE_REDIRECT @@ -80,21 +78,3 @@ func FromArgs_helper(dcn *domaintags.DomainNameVarieties, rec *models.RecordConf return nil } - -// The legacy system prepended a count to the name to coordinate ordering. - -var redirCount = map[string]int{} -var redirCountMutex = sync.RWMutex{} - -func incRedirCount(name string) { - redirCountMutex.Lock() - defer redirCountMutex.Unlock() - - redirCount[name]++ -} - -func getRedirCount(name string) int { - redirCountMutex.Lock() - defer redirCountMutex.Unlock() - return redirCount[name] -}