mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-09-20 06:46:19 +08:00
CLOUDFLAREAPI: CF_SINGLE_REDIRECT improvements: fix bugs, log translated redirects (#3051)
This commit is contained in:
parent
1d348de91c
commit
0869052419
14
commands/types/dnscontrol.d.ts
vendored
14
commands/types/dnscontrol.d.ts
vendored
|
@ -472,6 +472,11 @@ declare function CAA(name: string, tag: "issue" | "issuewild" | "iodef", value:
|
||||||
declare function CAA_BUILDER(opts: { label?: string; iodef: string; iodef_critical?: boolean; issue: string[]; issue_critical?: boolean; issuewild: string[]; issuewild_critical?: boolean; ttl?: Duration }): DomainModifier;
|
declare function CAA_BUILDER(opts: { label?: string; iodef: string; iodef_critical?: boolean; issue: string[]; issue_critical?: boolean; issuewild: string[]; issuewild_critical?: boolean; ttl?: Duration }): DomainModifier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
* `CF_REDIRECT` uses Cloudflare-specific features ("Forwarding URL" Page Rules) to
|
* `CF_REDIRECT` uses Cloudflare-specific features ("Forwarding URL" Page Rules) to
|
||||||
* generate a HTTP 301 permanent redirect.
|
* generate a HTTP 301 permanent redirect.
|
||||||
*
|
*
|
||||||
|
@ -533,6 +538,11 @@ declare function CF_REDIRECT(source: string, destination: string, ...modifiers:
|
||||||
declare function CF_SINGLE_REDIRECT(name: string, code: number, when: string, then: string, ...modifiers: RecordModifier[]): DomainModifier;
|
declare function CF_SINGLE_REDIRECT(name: string, code: number, when: string, then: string, ...modifiers: RecordModifier[]): DomainModifier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
* `CF_TEMP_REDIRECT` uses Cloudflare-specific features ("Forwarding URL" Page
|
* `CF_TEMP_REDIRECT` uses Cloudflare-specific features ("Forwarding URL" Page
|
||||||
* Rules) to generate a HTTP 302 temporary redirect.
|
* Rules) to generate a HTTP 302 temporary redirect.
|
||||||
*
|
*
|
||||||
|
@ -1810,7 +1820,7 @@ declare function LOC_BUILDER_STR(opts: { label?: string; str: string; alt?: numb
|
||||||
*
|
*
|
||||||
* ```javascript
|
* ```javascript
|
||||||
* D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER),
|
* D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER),
|
||||||
* M365_BUILDER({
|
* M365_BUILDER("example.com", {
|
||||||
* initialDomain: "example.onmicrosoft.com",
|
* initialDomain: "example.onmicrosoft.com",
|
||||||
* }),
|
* }),
|
||||||
* END);
|
* END);
|
||||||
|
@ -1822,7 +1832,7 @@ declare function LOC_BUILDER_STR(opts: { label?: string; str: string; alt?: numb
|
||||||
*
|
*
|
||||||
* ```javascript
|
* ```javascript
|
||||||
* D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER),
|
* D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER),
|
||||||
* M365_BUILDER({
|
* M365_BUILDER("example.com", {
|
||||||
* label: "test",
|
* label: "test",
|
||||||
* mx: false,
|
* mx: false,
|
||||||
* autodiscover: false,
|
* autodiscover: false,
|
||||||
|
|
|
@ -11,6 +11,13 @@ parameter_types:
|
||||||
"modifiers...": RecordModifier[]
|
"modifiers...": RecordModifier[]
|
||||||
---
|
---
|
||||||
|
|
||||||
|
{% hint style="warning" %}
|
||||||
|
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
|
`CF_REDIRECT` uses Cloudflare-specific features ("Forwarding URL" Page Rules) to
|
||||||
generate a HTTP 301 permanent redirect.
|
generate a HTTP 301 permanent redirect.
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,13 @@ parameter_types:
|
||||||
"modifiers...": RecordModifier[]
|
"modifiers...": RecordModifier[]
|
||||||
---
|
---
|
||||||
|
|
||||||
|
{% hint style="warning" %}
|
||||||
|
**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_TEMP_REDIRECT` uses Cloudflare-specific features ("Forwarding URL" Page
|
`CF_TEMP_REDIRECT` uses Cloudflare-specific features ("Forwarding URL" Page
|
||||||
Rules) to generate a HTTP 302 temporary redirect.
|
Rules) to generate a HTTP 302 temporary redirect.
|
||||||
|
|
||||||
|
|
|
@ -211,7 +211,8 @@ Enable it using:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var DSP_CLOUDFLARE = NewDnsProvider("cloudflare", {
|
var DSP_CLOUDFLARE = NewDnsProvider("cloudflare", {
|
||||||
"manage_redirects": true
|
"manage_redirects": true,
|
||||||
|
"transcode_log": "transcode.log",
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -231,8 +232,7 @@ New-style redirects ("Single Redirect Rules") are a new feature of DNSControl
|
||||||
as of v4.12.0 and may have bugs. Please test carefully.
|
as of v4.12.0 and may have bugs. Please test carefully.
|
||||||
{% endhint %}
|
{% endhint %}
|
||||||
|
|
||||||
|
### Conversion mode:
|
||||||
Conversion mode:
|
|
||||||
|
|
||||||
DNSControl can convert from old-style redirects (Page Rules) to new-style
|
DNSControl can convert from old-style redirects (Page Rules) to new-style
|
||||||
redirect (Single Redirects). To enable this mode, set both `manage_redirects`
|
redirect (Single Redirects). To enable this mode, set both `manage_redirects`
|
||||||
|
@ -268,7 +268,7 @@ via the CloudFlare control panel or wait for Cloudflare to remove support for th
|
||||||
|
|
||||||
{% hint style="warning" %}
|
{% hint style="warning" %}
|
||||||
Cloudflare's announcement says that they will convert old-style redirects (Page Rules) to new-style
|
Cloudflare's announcement says that they will convert old-style redirects (Page Rules) to new-style
|
||||||
redirect (Single Redirects) but they do not give a date for when this will happen. DNSControl
|
redirect (Single Redirects) but they do not give an exact date for when this will happen. DNSControl
|
||||||
will probably see these new redirects as foreign and delete them.
|
will probably see these new redirects as foreign and delete them.
|
||||||
|
|
||||||
Therefore it is probably safer to do the conversion ahead of them.
|
Therefore it is probably safer to do the conversion ahead of them.
|
||||||
|
@ -279,6 +279,54 @@ than DNSControl's. However there's no way for DNSControl to manage them since t
|
||||||
If you have suggestions on how to handle this better please file a bug.
|
If you have suggestions on how to handle this better please file a bug.
|
||||||
{% endhint %}
|
{% endhint %}
|
||||||
|
|
||||||
|
### Converting to CF_SINGLE_REDIRECT permanently
|
||||||
|
|
||||||
|
DNSControl will help convert `CF_REDIRECT`/`CF_TEMP_REDIRECT` statements into
|
||||||
|
`CF_SINGLE_REDIRECT` statements. You might choose to do this if you do not want
|
||||||
|
to rely on the automatic translation, or if you want to edit the results of the
|
||||||
|
translation.
|
||||||
|
|
||||||
|
DNSControl will generate a file of the translated statements if you specify
|
||||||
|
a filename using the `transcode_log` meta option.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var DSP_CLOUDFLARE = NewDnsProvider("cloudflare", {
|
||||||
|
"manage_single_redirects": true,
|
||||||
|
"transcode_log": "transcode.log",
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
After running `dnscontrol preview` the contents will look something like this:
|
||||||
|
|
||||||
|
{% code title="transcode.log" %}
|
||||||
|
```text
|
||||||
|
D("example.com", ...
|
||||||
|
CF_SINGLE_REDIRECT("1,302,https://example.com/*,https://replacement.example.com/$1",
|
||||||
|
302,
|
||||||
|
'http.host eq "example.com"',
|
||||||
|
'concat("https://replacement.example.com", http.request.uri.path)'
|
||||||
|
),
|
||||||
|
CF_SINGLE_REDIRECT("2,302,https://img.example.com/*,https://replacement.example.com/$1",
|
||||||
|
302,
|
||||||
|
'http.host eq "img.example.com"',
|
||||||
|
'concat("https://replacement.example.com", http.request.uri.path)'
|
||||||
|
),
|
||||||
|
CF_SINGLE_REDIRECT("3,302,https://i.example.com/*,https://replacement.example.com/$1",
|
||||||
|
302,
|
||||||
|
'http.host eq "i.example.com"',
|
||||||
|
'concat("https://replacement.example.com", http.request.uri.path)'
|
||||||
|
),
|
||||||
|
D("otherdomain.com", ...
|
||||||
|
CF_SINGLE_REDIRECT("1,301,https://one.otherdomain.com/,https://www.google.com/",
|
||||||
|
301,
|
||||||
|
'http.host eq "one.otherdomain.com" and http.request.uri.path eq "/"',
|
||||||
|
'concat("https://www.google.com/", "")'
|
||||||
|
),
|
||||||
|
```
|
||||||
|
{% endcode %}
|
||||||
|
|
||||||
|
Copying the statements to the proper place in `dnsconfig.js` is manual.
|
||||||
|
|
||||||
|
|
||||||
## Redirects
|
## Redirects
|
||||||
The Cloudflare provider can manage "Forwarding URL" Page Rules (redirects) for your domains. Simply use the `CF_REDIRECT` and `CF_TEMP_REDIRECT` functions to make redirects:
|
The Cloudflare provider can manage "Forwarding URL" Page Rules (redirects) for your domains. Simply use the `CF_REDIRECT` and `CF_TEMP_REDIRECT` functions to make redirects:
|
||||||
|
|
|
@ -503,7 +503,7 @@ func cfSingleRedirectEnabled() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func cfSingleRedirect(name string, code any, when, then string) *models.RecordConfig {
|
func cfSingleRedirect(name string, code any, when, then string) *models.RecordConfig {
|
||||||
r := makeRec("@", name, "CLOUDFLAREAPI_SINGLE_REDIRECT")
|
r := makeRec("@", name, cfsingleredirect.SINGLEREDIRECT)
|
||||||
err := cfsingleredirect.FromRaw(r, []any{name, code, when, then})
|
err := cfsingleredirect.FromRaw(r, []any{name, code, when, then})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("Should not happen... cfSingleRedirect")
|
panic("Should not happen... cfSingleRedirect")
|
||||||
|
@ -1947,6 +1947,7 @@ func makeTests() []*TestGroup {
|
||||||
tc("changecode", cfSingleRedirect(`name1`, `302`, `http.host eq "cnn.slackoverflow.com"`, `concat("https://www.cnn.com", http.request.uri.path)`)),
|
tc("changecode", cfSingleRedirect(`name1`, `302`, `http.host eq "cnn.slackoverflow.com"`, `concat("https://www.cnn.com", http.request.uri.path)`)),
|
||||||
tc("changewhen", cfSingleRedirect(`name1`, `302`, `http.host eq "msnbc.slackoverflow.com"`, `concat("https://www.cnn.com", http.request.uri.path)`)),
|
tc("changewhen", cfSingleRedirect(`name1`, `302`, `http.host eq "msnbc.slackoverflow.com"`, `concat("https://www.cnn.com", http.request.uri.path)`)),
|
||||||
tc("changethen", cfSingleRedirect(`name1`, `302`, `http.host eq "msnbc.slackoverflow.com"`, `concat("https://www.msnbc.com", http.request.uri.path)`)),
|
tc("changethen", cfSingleRedirect(`name1`, `302`, `http.host eq "msnbc.slackoverflow.com"`, `concat("https://www.msnbc.com", http.request.uri.path)`)),
|
||||||
|
tc("changename", cfSingleRedirect(`name1bis`, `302`, `http.host eq "msnbc.slackoverflow.com"`, `concat("https://www.msnbc.com", http.request.uri.path)`)),
|
||||||
),
|
),
|
||||||
|
|
||||||
// CLOUDFLAREAPI: PROXY
|
// CLOUDFLAREAPI: PROXY
|
||||||
|
|
|
@ -154,17 +154,18 @@ type CloudflareSingleRedirectConfig struct {
|
||||||
//
|
//
|
||||||
Code uint16 `json:"code,omitempty"` // 301 or 302
|
Code uint16 `json:"code,omitempty"` // 301 or 302
|
||||||
// PR == PageRule
|
// PR == PageRule
|
||||||
PRDisplay string `json:"pr_display,omitempty"` // How is this displayed to the user
|
|
||||||
PRWhen string `json:"pr_when,omitempty"`
|
PRWhen string `json:"pr_when,omitempty"`
|
||||||
PRThen string `json:"pr_then,omitempty"`
|
PRThen string `json:"pr_then,omitempty"`
|
||||||
PRPriority int `json:"pr_priority,omitempty"` // Really an identifier for the rule.
|
PRPriority int `json:"pr_priority,omitempty"` // Really an identifier for the rule.
|
||||||
|
PRDisplay string `json:"pr_display,omitempty"` // How is this displayed to the user (SetTarget) for CF_REDIRECT/CF_TEMP_REDIRECT
|
||||||
//
|
//
|
||||||
// SR == SingleRedirect
|
// SR == SingleRedirect
|
||||||
SRDisplay string `json:"sr_display,omitempty"` // How is this displayed to the user
|
SRName string `json:"sr_name,omitempty"` // How is this displayed to the user
|
||||||
SRWhen string `json:"sr_when,omitempty"`
|
SRWhen string `json:"sr_when,omitempty"`
|
||||||
SRThen string `json:"sr_then,omitempty"`
|
SRThen string `json:"sr_then,omitempty"`
|
||||||
SRRRulesetID string `json:"sr_rulesetid,omitempty"`
|
SRRRulesetID string `json:"sr_rulesetid,omitempty"`
|
||||||
SRRRulesetRuleID string `json:"sr_rulesetruleid,omitempty"`
|
SRRRulesetRuleID string `json:"sr_rulesetruleid,omitempty"`
|
||||||
|
SRDisplay string `json:"sr_display,omitempty"` // How is this displayed to the user (SetTarget) for CF_SINGLE_REDIRECT
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON marshals RecordConfig.
|
// MarshalJSON marshals RecordConfig.
|
||||||
|
|
|
@ -38,6 +38,7 @@ func PostProcess(domains []*models.DomainConfig) error {
|
||||||
|
|
||||||
case "CLOUDFLAREAPI_SINGLE_REDIRECT":
|
case "CLOUDFLAREAPI_SINGLE_REDIRECT":
|
||||||
err = cfsingleredirect.FromRaw(rec, rawRec.Args)
|
err = cfsingleredirect.FromRaw(rec, rawRec.Args)
|
||||||
|
rec.SetLabel("@", dc.Name)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("unknown rawrec type=%q", rawRec.Type)
|
err = fmt.Errorf("unknown rawrec type=%q", rawRec.Type)
|
||||||
|
|
|
@ -87,23 +87,17 @@ type cloudflareProvider struct {
|
||||||
cfClient *cloudflare.API
|
cfClient *cloudflare.API
|
||||||
//
|
//
|
||||||
manageSingleRedirects bool // New "Single Redirects"-style redirects.
|
manageSingleRedirects bool // New "Single Redirects"-style redirects.
|
||||||
|
//
|
||||||
|
// Used by
|
||||||
|
tcLogFilename string // Transcode Log file name
|
||||||
|
tcLogFh *os.File // Transcode Log file handle
|
||||||
|
tcZone string // Transcode Current zone
|
||||||
|
|
||||||
sync.Mutex // Protects all access to the following fields:
|
sync.Mutex // Protects all access to the following fields:
|
||||||
domainIndex map[string]string // Cache of zone name to zone ID.
|
domainIndex map[string]string // Cache of zone name to zone ID.
|
||||||
nameservers map[string][]string // Cache of zone name to list of nameservers.
|
nameservers map[string][]string // Cache of zone name to list of nameservers.
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(dlemenkov): remove this function after deleting all commented code referecing it
|
|
||||||
//func labelMatches(label string, matches []string) bool {
|
|
||||||
// printer.Debugf("DEBUG: labelMatches(%#v, %#v)\n", label, matches)
|
|
||||||
// for _, tst := range matches {
|
|
||||||
// if label == tst {
|
|
||||||
// return true
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return false
|
|
||||||
//}
|
|
||||||
|
|
||||||
// GetNameservers returns the nameservers for a domain.
|
// GetNameservers returns the nameservers for a domain.
|
||||||
func (c *cloudflareProvider) GetNameservers(domain string) ([]*models.Nameserver, error) {
|
func (c *cloudflareProvider) GetNameservers(domain string) ([]*models.Nameserver, error) {
|
||||||
|
|
||||||
|
@ -162,17 +156,6 @@ func (c *cloudflareProvider) GetZoneRecords(domain string, meta map[string]strin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// // FIXME(tlim) Why is this needed???
|
|
||||||
// // I don't know. Let's comment it out and see if anything breaks.
|
|
||||||
// for i := len(records) - 1; i >= 0; i-- {
|
|
||||||
// rec := records[i]
|
|
||||||
// // Delete ignore labels
|
|
||||||
// if labelMatches(dnsutil.TrimDomainName(rec.Original.(cloudflare.DNSRecord).Name, dc.Name), c.ignoredLabels) {
|
|
||||||
// printer.Debugf("ignored_label: %s\n", rec.Original.(cloudflare.DNSRecord).Name)
|
|
||||||
// records = append(records[:i], records[i+1:]...)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
if c.manageRedirects { // if old
|
if c.manageRedirects { // if old
|
||||||
prs, err := c.getPageRules(domainID, domain)
|
prs, err := c.getPageRules(domainID, domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -183,14 +166,11 @@ func (c *cloudflareProvider) GetZoneRecords(domain string, meta map[string]strin
|
||||||
|
|
||||||
if c.manageSingleRedirects { // if new xor old
|
if c.manageSingleRedirects { // if new xor old
|
||||||
// Download the list of Single Redirects.
|
// Download the list of Single Redirects.
|
||||||
// For each one, generate a CLOUDFLAREAPI_SINGLE_REDIRECT record
|
// For each one, generate a SINGLEREDIRECT record
|
||||||
// Append these records to `records`
|
|
||||||
prs, err := c.getSingleRedirects(domainID, domain)
|
prs, err := c.getSingleRedirects(domainID, domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
//printer.Printf("DEBUG: Single Redirects")
|
|
||||||
//fmt.Fprintf(os.Stdout, "DEBUG: Single Redirects")
|
|
||||||
records = append(records, prs...)
|
records = append(records, prs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,8 +264,6 @@ func (c *cloudflareProvider) GetZoneRecordsCorrections(dc *models.DomainConfig,
|
||||||
case diff2.DELETE:
|
case diff2.DELETE:
|
||||||
deleteRec := inst.Old[0]
|
deleteRec := inst.Old[0]
|
||||||
deleteRecType := deleteRec.Type
|
deleteRecType := deleteRec.Type
|
||||||
//deleteRecOrig := deleteRec.Original
|
|
||||||
//corrs = c.mkDeleteCorrection(deleteRecType, deleteRecOrig, domainID, msg)
|
|
||||||
corrs = c.mkDeleteCorrection(deleteRecType, deleteRec, domainID, msg)
|
corrs = c.mkDeleteCorrection(deleteRecType, deleteRec, domainID, msg)
|
||||||
// DS records must always have a corresponding NS record.
|
// DS records must always have a corresponding NS record.
|
||||||
// Therefore, we remove DS records before any NS records.
|
// Therefore, we remove DS records before any NS records.
|
||||||
|
@ -344,10 +322,7 @@ func (c *cloudflareProvider) mkCreateCorrection(newrec *models.RecordConfig, dom
|
||||||
Msg: msg,
|
Msg: msg,
|
||||||
F: func() error { return c.createWorkerRoute(domainID, newrec.GetTargetField()) },
|
F: func() error { return c.createWorkerRoute(domainID, newrec.GetTargetField()) },
|
||||||
}}
|
}}
|
||||||
case "CLOUDFLAREAPI_SINGLE_REDIRECT":
|
case cfsingleredirect.SINGLEREDIRECT:
|
||||||
//fmt.Printf("DEBUG: mkCreateSingleRedir: newrec=%+v\n", *newrec)
|
|
||||||
//fmt.Printf("DEBUG: mkCreateSingleRedir: crn=%+v\n", (*newrec).CloudflareRedirect)
|
|
||||||
//fmt.Printf("DEBUG: mkCreateSingleRedir: cr=%+v\n", (*newrec).CloudflareRedirect)
|
|
||||||
return []*models.Correction{{
|
return []*models.Correction{{
|
||||||
Msg: msg,
|
Msg: msg,
|
||||||
F: func() error {
|
F: func() error {
|
||||||
|
@ -367,8 +342,7 @@ func (c *cloudflareProvider) mkChangeCorrection(oldrec, newrec *models.RecordCon
|
||||||
idTxt = oldrec.Original.(cloudflare.PageRule).ID
|
idTxt = oldrec.Original.(cloudflare.PageRule).ID
|
||||||
case "WORKER_ROUTE":
|
case "WORKER_ROUTE":
|
||||||
idTxt = oldrec.Original.(cloudflare.WorkerRoute).ID
|
idTxt = oldrec.Original.(cloudflare.WorkerRoute).ID
|
||||||
case "CLOUDFLAREAPI_SINGLE_REDIRECT":
|
case cfsingleredirect.SINGLEREDIRECT:
|
||||||
//idTxt = oldrec.Original.(cloudflare.RulesetRule).ID
|
|
||||||
idTxt = oldrec.CloudflareRedirect.SRRRulesetID
|
idTxt = oldrec.CloudflareRedirect.SRRRulesetID
|
||||||
default:
|
default:
|
||||||
idTxt = oldrec.Original.(cloudflare.DNSRecord).ID
|
idTxt = oldrec.Original.(cloudflare.DNSRecord).ID
|
||||||
|
@ -383,7 +357,7 @@ func (c *cloudflareProvider) mkChangeCorrection(oldrec, newrec *models.RecordCon
|
||||||
return c.updatePageRule(idTxt, domainID, *newrec.CloudflareRedirect)
|
return c.updatePageRule(idTxt, domainID, *newrec.CloudflareRedirect)
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
case "CLOUDFLAREAPI_SINGLE_REDIRECT":
|
case cfsingleredirect.SINGLEREDIRECT:
|
||||||
return []*models.Correction{{
|
return []*models.Correction{{
|
||||||
Msg: msg,
|
Msg: msg,
|
||||||
F: func() error {
|
F: func() error {
|
||||||
|
@ -416,7 +390,7 @@ func (c *cloudflareProvider) mkDeleteCorrection(recType string, origRec *models.
|
||||||
idTxt = origRec.Original.(cloudflare.PageRule).ID
|
idTxt = origRec.Original.(cloudflare.PageRule).ID
|
||||||
case "WORKER_ROUTE":
|
case "WORKER_ROUTE":
|
||||||
idTxt = origRec.Original.(cloudflare.WorkerRoute).ID
|
idTxt = origRec.Original.(cloudflare.WorkerRoute).ID
|
||||||
case "CLOUDFLAREAPI_SINGLE_REDIRECT":
|
case cfsingleredirect.SINGLEREDIRECT:
|
||||||
idTxt = origRec.Original.(cloudflare.RulesetRule).ID
|
idTxt = origRec.Original.(cloudflare.RulesetRule).ID
|
||||||
default:
|
default:
|
||||||
idTxt = origRec.Original.(cloudflare.DNSRecord).ID
|
idTxt = origRec.Original.(cloudflare.DNSRecord).ID
|
||||||
|
@ -431,12 +405,7 @@ func (c *cloudflareProvider) mkDeleteCorrection(recType string, origRec *models.
|
||||||
return c.deletePageRule(origRec.Original.(cloudflare.PageRule).ID, domainID)
|
return c.deletePageRule(origRec.Original.(cloudflare.PageRule).ID, domainID)
|
||||||
case "WORKER_ROUTE":
|
case "WORKER_ROUTE":
|
||||||
return c.deleteWorkerRoute(origRec.Original.(cloudflare.WorkerRoute).ID, domainID)
|
return c.deleteWorkerRoute(origRec.Original.(cloudflare.WorkerRoute).ID, domainID)
|
||||||
case "CLOUDFLAREAPI_SINGLE_REDIRECT":
|
case cfsingleredirect.SINGLEREDIRECT:
|
||||||
//o := origRec.Original.(cloudflare.Ruleset)
|
|
||||||
//printer.Printf("DEBUG: DELETE %+v\n", o)
|
|
||||||
// printer.Printf("DEBUG: DELETE ID = %+v\n", o.ID)
|
|
||||||
// printer.Printf("DEBUG: DELETE ACTION %+v\n", o.ActionParameters)
|
|
||||||
// printer.Printf("DEBUG: DELETE FROMVALUE %+v\n", o.ActionParameters.FromValue)
|
|
||||||
return c.deleteSingleRedirects(domainID, *origRec.CloudflareRedirect)
|
return c.deleteSingleRedirects(domainID, *origRec.CloudflareRedirect)
|
||||||
default:
|
default:
|
||||||
return c.deleteDNSRecord(origRec.Original.(cloudflare.DNSRecord), domainID)
|
return c.deleteDNSRecord(origRec.Original.(cloudflare.DNSRecord), domainID)
|
||||||
|
@ -530,7 +499,7 @@ func (c *cloudflareProvider) preprocessConfig(dc *models.DomainConfig) error {
|
||||||
// A and CNAMEs: Validate. If null, set to default.
|
// A and CNAMEs: Validate. If null, set to default.
|
||||||
// else: Make sure it wasn't set. Set to default.
|
// else: Make sure it wasn't set. Set to default.
|
||||||
// iterate backwards so first defined page rules have highest priority
|
// iterate backwards so first defined page rules have highest priority
|
||||||
currentPrPrio := 1
|
prPriority := 0
|
||||||
for i := len(dc.Records) - 1; i >= 0; i-- {
|
for i := len(dc.Records) - 1; i >= 0; i-- {
|
||||||
rec := dc.Records[i]
|
rec := dc.Records[i]
|
||||||
if rec.Metadata == nil {
|
if rec.Metadata == nil {
|
||||||
|
@ -564,9 +533,7 @@ func (c *cloudflareProvider) preprocessConfig(dc *models.DomainConfig) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CF_REDIRECT record types. Encode target as
|
// CF_REDIRECT record types:
|
||||||
// $FROM,$TO,$PRIO,$CODE or build Cfsr struct for new-style
|
|
||||||
// (Single Redirect) versions.
|
|
||||||
if rec.Type == "CF_REDIRECT" || rec.Type == "CF_TEMP_REDIRECT" {
|
if rec.Type == "CF_REDIRECT" || rec.Type == "CF_TEMP_REDIRECT" {
|
||||||
if !c.manageRedirects && !c.manageSingleRedirects {
|
if !c.manageRedirects && !c.manageSingleRedirects {
|
||||||
return fmt.Errorf("you must add 'manage_single_redirects: true' metadata to cloudflare provider to use CF_REDIRECT/CF_TEMP_REDIRECT records")
|
return fmt.Errorf("you must add 'manage_single_redirects: true' metadata to cloudflare provider to use CF_REDIRECT/CF_TEMP_REDIRECT records")
|
||||||
|
@ -576,65 +543,49 @@ func (c *cloudflareProvider) preprocessConfig(dc *models.DomainConfig) error {
|
||||||
code = 302
|
code = 302
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.manageRedirects && !c.manageSingleRedirects {
|
part := strings.SplitN(rec.GetTargetField(), ",", 2)
|
||||||
// Old-Style only. Convert this record to PAGE_RULE.
|
prWhen, prThen := part[0], part[1]
|
||||||
//printer.Printf("DEBUG: prepro() target=%q\n", rec.GetTargetField())
|
prPriority++
|
||||||
sr, err := cfsingleredirect.FromUserInput(rec.GetTargetField(), code, currentPrPrio)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fixPageRule(rec, sr)
|
|
||||||
currentPrPrio++
|
|
||||||
} else if !c.manageRedirects && c.manageSingleRedirects {
|
|
||||||
// New-Style only. Convert this record to a CLOUDFLAREAPI_SINGLE_REDIRECT.
|
|
||||||
sr, err := cfsingleredirect.FromUserInput(rec.GetTargetField(), code, currentPrPrio)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = fixSingleRedirect(rec, sr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Both! Convert this record to PAGE_RULE and append an additional CLOUDFLAREAPI_SINGLE_REDIRECT.
|
|
||||||
|
|
||||||
target := rec.GetTargetField()
|
// Convert this record to a PAGE_RULE.
|
||||||
|
cfsingleredirect.MakePageRule(rec, prPriority, code, prWhen, prThen)
|
||||||
|
rec.SetLabel("@", dc.Name)
|
||||||
|
|
||||||
|
if c.manageRedirects && !c.manageSingleRedirects {
|
||||||
|
// Old-Style only. No additional work needed.
|
||||||
|
|
||||||
|
} else if !c.manageRedirects && c.manageSingleRedirects {
|
||||||
|
// New-Style only. Convert PAGE_RULE to SINGLEREDIRECT.
|
||||||
|
cfsingleredirect.TranscodePRtoSR(rec)
|
||||||
|
if err := c.LogTranscode(dc.Name, rec.CloudflareRedirect); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Both old-style and new-style enabled!
|
||||||
|
// Retain the PAGE_RULE and append an additional SINGLEREDIRECT.
|
||||||
|
|
||||||
// make a copy:
|
// make a copy:
|
||||||
newRec, err := rec.Copy()
|
newRec, err := rec.Copy()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// The copy becomes the CF SingleRedirect
|
// The copy becomes the CF SingleRedirect
|
||||||
sr, err := cfsingleredirect.FromUserInput(target, code, currentPrPrio)
|
cfsingleredirect.TranscodePRtoSR(rec)
|
||||||
if err != nil {
|
if err := c.LogTranscode(dc.Name, rec.CloudflareRedirect); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = fixSingleRedirect(newRec, sr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append the copy to the end of the list.
|
// Append the copy to the end of the list.
|
||||||
dc.Records = append(dc.Records, newRec)
|
dc.Records = append(dc.Records, newRec)
|
||||||
|
|
||||||
// The original becomes the PAGE_RULE:
|
// The original PAGE_RULE remains untouched.
|
||||||
sr, err = cfsingleredirect.FromUserInput(target, code, currentPrPrio)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fixPageRule(rec, sr)
|
|
||||||
currentPrPrio++
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if rec.Type == "CLOUDFLAREAPI_SINGLE_REDIRECT" {
|
} else if rec.Type == cfsingleredirect.SINGLEREDIRECT {
|
||||||
// CLOUDFLAREAPI_SINGLE_REDIRECT record types.
|
// SINGLEREDIRECT record types. Verify they are enabled.
|
||||||
if !c.manageSingleRedirects {
|
if !c.manageSingleRedirects {
|
||||||
return fmt.Errorf("you must add 'manage_single_redirects: true' metadata to cloudflare provider to use CF_SINGLE__REDIRECT records")
|
return fmt.Errorf("you must add 'manage_single_redirects: true' metadata to cloudflare provider to use CF_SINGLE__REDIRECT records")
|
||||||
}
|
}
|
||||||
// Nothing needs to be done.
|
|
||||||
|
|
||||||
} else if rec.Type == "CF_WORKER_ROUTE" {
|
} else if rec.Type == "CF_WORKER_ROUTE" {
|
||||||
// CF_WORKER_ROUTE record types. Encode target as $PATTERN,$SCRIPT
|
// CF_WORKER_ROUTE record types. Encode target as $PATTERN,$SCRIPT
|
||||||
|
@ -672,20 +623,35 @@ func (c *cloudflareProvider) preprocessConfig(dc *models.DomainConfig) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fixPageRule(rc *models.RecordConfig, sr *models.CloudflareSingleRedirectConfig) {
|
func (c *cloudflareProvider) LogTranscode(zone string, redirect *models.CloudflareSingleRedirectConfig) error {
|
||||||
rc.Type = "PAGE_RULE"
|
// No filename? Don't log anything.
|
||||||
rc.TTL = 1
|
filename := c.tcLogFilename
|
||||||
rc.SetTarget(sr.PRDisplay)
|
if filename == "" {
|
||||||
rc.CloudflareRedirect = sr
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fixSingleRedirect(rc *models.RecordConfig, sr *models.CloudflareSingleRedirectConfig) error {
|
// File not opened already? Open it.
|
||||||
rc.Type = "CLOUDFLAREAPI_SINGLE_REDIRECT"
|
if c.tcLogFh == nil {
|
||||||
rc.TTL = 1
|
f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
|
||||||
rc.SetTarget(sr.SRDisplay)
|
if err != nil {
|
||||||
rc.CloudflareRedirect = sr
|
return err
|
||||||
|
}
|
||||||
|
c.tcLogFh = f
|
||||||
|
}
|
||||||
|
fh := c.tcLogFh
|
||||||
|
|
||||||
err := cfsingleredirect.AddNewStyleFields(sr)
|
// Output "D(zone)" if needed.
|
||||||
|
var text string
|
||||||
|
if c.tcZone != zone {
|
||||||
|
text = fmt.Sprintf("D(%q, ...\n", zone)
|
||||||
|
}
|
||||||
|
c.tcZone = zone
|
||||||
|
|
||||||
|
// Generate the new command and output.
|
||||||
|
text = text + fmt.Sprintf(" CF_SINGLE_REDIRECT(%q,\n %03d,\n '%s',\n '%s'\n ),\n",
|
||||||
|
redirect.SRName, redirect.Code,
|
||||||
|
redirect.SRWhen, redirect.SRThen)
|
||||||
|
_, err := fh.WriteString(text)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -733,6 +699,7 @@ func newCloudflare(m map[string]string, metadata json.RawMessage) (providers.DNS
|
||||||
ManageWorkers bool `json:"manage_workers"`
|
ManageWorkers bool `json:"manage_workers"`
|
||||||
//
|
//
|
||||||
ManageSingleRedirects bool `json:"manage_single_redirects"` // New-style Dynamic "Single Redirects"
|
ManageSingleRedirects bool `json:"manage_single_redirects"` // New-style Dynamic "Single Redirects"
|
||||||
|
TranscodeLogFilename string `json:"transcode_log"` // Log the PAGE_RULE conversions.
|
||||||
}{}
|
}{}
|
||||||
err := json.Unmarshal([]byte(metadata), parsedMeta)
|
err := json.Unmarshal([]byte(metadata), parsedMeta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -740,6 +707,7 @@ func newCloudflare(m map[string]string, metadata json.RawMessage) (providers.DNS
|
||||||
}
|
}
|
||||||
api.manageSingleRedirects = parsedMeta.ManageSingleRedirects
|
api.manageSingleRedirects = parsedMeta.ManageSingleRedirects
|
||||||
api.manageRedirects = parsedMeta.ManageRedirects
|
api.manageRedirects = parsedMeta.ManageRedirects
|
||||||
|
api.tcLogFilename = parsedMeta.TranscodeLogFilename
|
||||||
api.manageWorkers = parsedMeta.ManageWorkers
|
api.manageWorkers = parsedMeta.ManageWorkers
|
||||||
// ignored_labels:
|
// ignored_labels:
|
||||||
api.ignoredLabels = append(api.ignoredLabels, parsedMeta.IgnoredLabels...)
|
api.ignoredLabels = append(api.ignoredLabels, parsedMeta.IgnoredLabels...)
|
||||||
|
|
|
@ -286,38 +286,28 @@ func (c *cloudflareProvider) getSingleRedirects(id string, domain string) ([]*mo
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("failed fetching redirect rule list cloudflare: %s (%T)", err, err)
|
return nil, fmt.Errorf("failed fetching redirect rule list cloudflare: %s (%T)", err, err)
|
||||||
}
|
}
|
||||||
//var rulelist []cloudflare.RulesetRule
|
|
||||||
//rulelist = rules.Rules
|
|
||||||
//rulelist := rules.Rules
|
|
||||||
|
|
||||||
//printer.Printf("DEBUG: rules %+v\n", rules)
|
|
||||||
recs := []*models.RecordConfig{}
|
recs := []*models.RecordConfig{}
|
||||||
for _, pr := range rules.Rules {
|
for _, pr := range rules.Rules {
|
||||||
//printer.Printf("DEBUG: %+v\n", pr)
|
|
||||||
|
|
||||||
var thisPr = pr
|
var thisPr = pr
|
||||||
r := &models.RecordConfig{
|
r := &models.RecordConfig{
|
||||||
Type: "CLOUDFLAREAPI_SINGLE_REDIRECT",
|
|
||||||
Original: thisPr,
|
Original: thisPr,
|
||||||
TTL: 1,
|
|
||||||
}
|
}
|
||||||
r.SetLabel("@", domain)
|
|
||||||
|
|
||||||
// Extract the valuables from the rule, use it to make the sr:
|
// Extract the valuables from the rule, use it to make the sr:
|
||||||
|
srName := pr.Description
|
||||||
srWhen := pr.Expression
|
srWhen := pr.Expression
|
||||||
srThen := pr.ActionParameters.FromValue.TargetURL.Expression
|
srThen := pr.ActionParameters.FromValue.TargetURL.Expression
|
||||||
code := uint16(pr.ActionParameters.FromValue.StatusCode)
|
code := uint16(pr.ActionParameters.FromValue.StatusCode)
|
||||||
sr := cfsingleredirect.FromAPIData(srWhen, srThen, code)
|
|
||||||
//sr.SRRRuleList = rulelist
|
|
||||||
//printer.Printf("DEBUG: DESCRIPTION = %v\n", pr.Description)
|
|
||||||
sr.SRDisplay = pr.Description
|
|
||||||
// printer.Printf("DEBUG: PR = %+v\n", pr)
|
|
||||||
// printer.Printf("DEBUG: rules = %+v\n", rules)
|
|
||||||
sr.SRRRulesetID = rules.ID
|
|
||||||
sr.SRRRulesetRuleID = pr.ID //correct
|
|
||||||
|
|
||||||
r.CloudflareRedirect = sr
|
cfsingleredirect.MakeSingleRedirectFromAPI(r, code, srName, srWhen, srThen)
|
||||||
r.SetTarget(pr.Description)
|
r.SetLabel("@", domain)
|
||||||
|
|
||||||
|
// Store the IDs
|
||||||
|
sr := r.CloudflareRedirect
|
||||||
|
sr.SRRRulesetID = rules.ID
|
||||||
|
sr.SRRRulesetRuleID = pr.ID
|
||||||
|
|
||||||
recs = append(recs, r)
|
recs = append(recs, r)
|
||||||
}
|
}
|
||||||
|
@ -327,9 +317,6 @@ func (c *cloudflareProvider) getSingleRedirects(id string, domain string) ([]*mo
|
||||||
|
|
||||||
func (c *cloudflareProvider) createSingleRedirect(domainID string, cfr models.CloudflareSingleRedirectConfig) error {
|
func (c *cloudflareProvider) createSingleRedirect(domainID string, cfr models.CloudflareSingleRedirectConfig) error {
|
||||||
|
|
||||||
//printer.Printf("DEBUG: createSingleRedir: d=%v crf=%+v\n", domainID, cfr)
|
|
||||||
// Asumption for target:
|
|
||||||
|
|
||||||
newSingleRedirectRulesActionParameters := cloudflare.RulesetRuleActionParameters{}
|
newSingleRedirectRulesActionParameters := cloudflare.RulesetRuleActionParameters{}
|
||||||
newSingleRedirectRule := cloudflare.RulesetRule{}
|
newSingleRedirectRule := cloudflare.RulesetRule{}
|
||||||
newSingleRedirectRules := []cloudflare.RulesetRule{}
|
newSingleRedirectRules := []cloudflare.RulesetRule{}
|
||||||
|
@ -347,7 +334,8 @@ func (c *cloudflareProvider) createSingleRedirect(domainID string, cfr models.Cl
|
||||||
// Redirect expression
|
// Redirect expression
|
||||||
newSingleRedirectRulesActionParameters.FromValue.TargetURL.Expression = cfr.SRThen
|
newSingleRedirectRulesActionParameters.FromValue.TargetURL.Expression = cfr.SRThen
|
||||||
// Redirect name
|
// Redirect name
|
||||||
newSingleRedirectRules[0].Description = cfr.SRDisplay
|
newSingleRedirectRules[0].Description = cfr.SRName
|
||||||
|
|
||||||
// Rule action, should always be redirect in this case
|
// Rule action, should always be redirect in this case
|
||||||
newSingleRedirectRules[0].Action = "redirect"
|
newSingleRedirectRules[0].Action = "redirect"
|
||||||
// Phase should always be http_request_dynamic_redirect
|
// Phase should always be http_request_dynamic_redirect
|
||||||
|
@ -401,7 +389,7 @@ func (c *cloudflareProvider) deleteSingleRedirects(domainID string, cfr models.C
|
||||||
//printer.Printf("DEBUG: CALLING API DeleteRulesetRule: SRRRulesetID=%v, cfr.SRRRulesetRuleID=%v\n", cfr.SRRRulesetID, cfr.SRRRulesetRuleID)
|
//printer.Printf("DEBUG: CALLING API DeleteRulesetRule: SRRRulesetID=%v, cfr.SRRRulesetRuleID=%v\n", cfr.SRRRulesetID, cfr.SRRRulesetRuleID)
|
||||||
|
|
||||||
err := c.cfClient.DeleteRulesetRule(context.Background(), cloudflare.ZoneIdentifier(domainID), cfr.SRRRulesetID, cfr.SRRRulesetRuleID)
|
err := c.cfClient.DeleteRulesetRule(context.Background(), cloudflare.ZoneIdentifier(domainID), cfr.SRRRulesetID, cfr.SRRRulesetRuleID)
|
||||||
// TODO(tlim): This is terrible. It returns an error even when it is successful.
|
// NB(tlim): Yuck. This returns an error even when it is successful. Dig into the JSON for the real status.
|
||||||
if strings.Contains(err.Error(), `"success": true,`) {
|
if strings.Contains(err.Error(), `"success": true,`) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -410,13 +398,9 @@ func (c *cloudflareProvider) deleteSingleRedirects(domainID string, cfr models.C
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cloudflareProvider) updateSingleRedirect(domainID string, oldrec, newrec *models.RecordConfig) error {
|
func (c *cloudflareProvider) updateSingleRedirect(domainID string, oldrec, newrec *models.RecordConfig) error {
|
||||||
// rulesetID := cfr.SRRRulesetID
|
|
||||||
// rulesetRuleID := cfr.SRRRulesetRuleID
|
|
||||||
//printer.Printf("DEBUG: UPDATE-DEL domID=%v sr=%+v\n", domainID, cfr)
|
|
||||||
if err := c.deleteSingleRedirects(domainID, *oldrec.CloudflareRedirect); err != nil {
|
if err := c.deleteSingleRedirects(domainID, *oldrec.CloudflareRedirect); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
//printer.Printf("DEBUG: UPDATE-CREATE domID=%v sr=%+v\n", domainID, newrec.CloudflareRedirect)
|
|
||||||
return c.createSingleRedirect(domainID, *newrec.CloudflareRedirect)
|
return c.createSingleRedirect(domainID, *newrec.CloudflareRedirect)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,24 +421,17 @@ func (c *cloudflareProvider) getPageRules(id string, domain string) ([]*models.R
|
||||||
value := pr.Actions[0].Value.(map[string]interface{})
|
value := pr.Actions[0].Value.(map[string]interface{})
|
||||||
var thisPr = pr
|
var thisPr = pr
|
||||||
r := &models.RecordConfig{
|
r := &models.RecordConfig{
|
||||||
Type: "PAGE_RULE",
|
|
||||||
Original: thisPr,
|
Original: thisPr,
|
||||||
TTL: 1,
|
|
||||||
}
|
}
|
||||||
r.SetLabel("@", domain)
|
|
||||||
code := intZero(value["status_code"])
|
|
||||||
raw := fmt.Sprintf("%s,%s,%d,%d", // $FROM,$TO,$PRIO,$CODE
|
|
||||||
pr.Targets[0].Constraint.Value,
|
|
||||||
value["url"],
|
|
||||||
pr.Priority,
|
|
||||||
code)
|
|
||||||
r.SetTarget(raw)
|
|
||||||
|
|
||||||
cr, err := cfsingleredirect.FromUserInput(raw, code, pr.Priority)
|
code := intZero(value["status_code"])
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
when := pr.Targets[0].Constraint.Value
|
||||||
}
|
then := value["url"].(string)
|
||||||
r.CloudflareRedirect = cr
|
currentPrPrio := pr.Priority
|
||||||
|
|
||||||
|
cfsingleredirect.MakePageRule(r, currentPrPrio, code, when, then)
|
||||||
|
r.SetLabel("@", domain)
|
||||||
|
|
||||||
recs = append(recs, r)
|
recs = append(recs, r)
|
||||||
}
|
}
|
||||||
|
@ -492,7 +469,6 @@ func (c *cloudflareProvider) createPageRule(domainID string, cfr models.Cloudfla
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
//printer.Printf("DEBUG: createPageRule pr=%+v\n", pr)
|
|
||||||
_, err := c.cfClient.CreatePageRule(context.Background(), domainID, pr)
|
_, err := c.cfClient.CreatePageRule(context.Background(), domainID, pr)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,14 @@ import (
|
||||||
"github.com/StackExchange/dnscontrol/v4/pkg/rtypecontrol"
|
"github.com/StackExchange/dnscontrol/v4/pkg/rtypecontrol"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SINGLEREDIRECT is the string name for this rType.
|
||||||
|
const SINGLEREDIRECT = "CLOUDFLAREAPI_SINGLE_REDIRECT"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rtypecontrol.Register("CLOUDFLAREAPI_SINGLE_REDIRECT")
|
rtypecontrol.Register(SINGLEREDIRECT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FromRaw convert RecordConfig using data from a RawRecordConfig's parameters.
|
||||||
func FromRaw(rc *models.RecordConfig, items []any) error {
|
func FromRaw(rc *models.RecordConfig, items []any) error {
|
||||||
|
|
||||||
// Validate types.
|
// Validate types.
|
||||||
|
@ -23,17 +27,14 @@ func FromRaw(rc *models.RecordConfig, items []any) error {
|
||||||
var code uint16
|
var code uint16
|
||||||
|
|
||||||
name = items[0].(string)
|
name = items[0].(string)
|
||||||
|
|
||||||
code = items[1].(uint16)
|
code = items[1].(uint16)
|
||||||
if code != 301 && code != 302 {
|
if code != 301 && code != 302 {
|
||||||
return fmt.Errorf("code (%03d) is not 301 or 302", code)
|
return fmt.Errorf("code (%03d) is not 301 or 302", code)
|
||||||
}
|
}
|
||||||
|
when = items[2].(string)
|
||||||
|
then = items[3].(string)
|
||||||
|
|
||||||
when, then = items[2].(string), items[3].(string)
|
makeSingleRedirectFromRawRec(rc, code, name, when, then)
|
||||||
|
|
||||||
rc.Name = name
|
|
||||||
rc.CloudflareRedirect = FromAPIData(when, then, code)
|
|
||||||
rc.SetTarget(rc.CloudflareRedirect.SRDisplay)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,51 +9,29 @@ import (
|
||||||
"github.com/StackExchange/dnscontrol/v4/models"
|
"github.com/StackExchange/dnscontrol/v4/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
func FromUserInput(target string, code uint16, priority int) (*models.CloudflareSingleRedirectConfig, error) {
|
// TranscodePRtoSR takes a PAGE_RULE record, stores transcoded versions of the fields, and makes the record a CLOUDFLAREAPI_SINGLE_REDDIRECT.
|
||||||
// target: matcher,replacement,priority,code
|
func TranscodePRtoSR(rec *models.RecordConfig) error {
|
||||||
// target: cable.slackoverflow.com/*,https://change.cnn.com/$1,1,302
|
rec.Type = SINGLEREDIRECT // This record is now a CLOUDFLAREAPI_SINGLE_REDIRECT
|
||||||
|
|
||||||
r := &models.CloudflareSingleRedirectConfig{}
|
|
||||||
|
|
||||||
// Break apart the 4-part string and store into the individual fields:
|
|
||||||
parts := strings.Split(target, ",")
|
|
||||||
//printer.Printf("DEBUG: cfsrFromOldStyle: parts=%v\n", parts)
|
|
||||||
r.PRDisplay = fmt.Sprintf("%s,%d,%03d", target, priority, code)
|
|
||||||
r.PRWhen = parts[0]
|
|
||||||
r.PRThen = parts[1]
|
|
||||||
r.PRPriority = priority
|
|
||||||
r.Code = code
|
|
||||||
|
|
||||||
// Convert old-style to new-style:
|
|
||||||
if err := AddNewStyleFields(r); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return r, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddNewStyleFields takes a PAGE_RULE-style target and populates the CFSRC.
|
|
||||||
func AddNewStyleFields(sr *models.CloudflareSingleRedirectConfig) error {
|
|
||||||
|
|
||||||
// Extract the fields we're reading from:
|
// Extract the fields we're reading from:
|
||||||
|
sr := rec.CloudflareRedirect
|
||||||
|
code := sr.Code
|
||||||
prWhen := sr.PRWhen
|
prWhen := sr.PRWhen
|
||||||
prThen := sr.PRThen
|
prThen := sr.PRThen
|
||||||
code := sr.Code
|
srName := sr.PRDisplay
|
||||||
|
|
||||||
// Convert old-style patterns to new-style rules:
|
// Convert old-style patterns to new-style rules:
|
||||||
srWhen, srThen, err := makeRuleFromPattern(prWhen, prThen)
|
srWhen, srThen, err := makeRuleFromPattern(prWhen, prThen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
display := fmt.Sprintf(`%s,%s,%d,%03d matcher=%s replacement=%s`,
|
|
||||||
prWhen, prThen,
|
|
||||||
sr.PRPriority, code,
|
|
||||||
srWhen, srThen,
|
|
||||||
)
|
|
||||||
|
|
||||||
// Store the results in the fields we're writing to:
|
// Fix the RecordConfig
|
||||||
sr.SRWhen = srWhen
|
makeSingleRedirectFromConvert(rec,
|
||||||
sr.SRThen = srThen
|
sr.PRPriority,
|
||||||
sr.SRDisplay = display
|
prWhen, prThen,
|
||||||
|
code,
|
||||||
|
srName, srWhen, srThen)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,15 +94,6 @@ func Test_makeSingleDirectRule(t *testing.T) {
|
||||||
wantExpr: `concat("https://survey.stackoverflow.co/2021", "")`,
|
wantExpr: `concat("https://survey.stackoverflow.co/2021", "")`,
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
// {
|
|
||||||
// name: "27",
|
|
||||||
// pattern: "*www.stackoverflow.help/*",
|
|
||||||
// replace: "https://stackoverflow.help/$1",
|
|
||||||
/// FIXME(tlim): Should "$1" should be a "$2"? See dnsconfig.js:4344
|
|
||||||
// wantMatch: `FIXME`,
|
|
||||||
// wantExpr: `FIXME`,
|
|
||||||
// wantErr: false,
|
|
||||||
// },
|
|
||||||
{
|
{
|
||||||
name: "28",
|
name: "28",
|
||||||
pattern: "*stackoverflow.help/support/solutions/articles/36000241656-write-an-article",
|
pattern: "*stackoverflow.help/support/solutions/articles/36000241656-write-an-article",
|
||||||
|
|
122
providers/cloudflare/rtypes/cfsingleredirect/from.go
Normal file
122
providers/cloudflare/rtypes/cfsingleredirect/from.go
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
package cfsingleredirect
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/StackExchange/dnscontrol/v4/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MakePageRule updates a RecordConfig to be a PAGE_RULE using PAGE_RULE data.
|
||||||
|
func MakePageRule(rc *models.RecordConfig, priority int, code uint16, when, then string) {
|
||||||
|
display := mkPageRuleBlob(priority, code, when, then)
|
||||||
|
|
||||||
|
rc.Type = "PAGE_RULE"
|
||||||
|
rc.TTL = 1
|
||||||
|
rc.CloudflareRedirect = &models.CloudflareSingleRedirectConfig{
|
||||||
|
Code: code,
|
||||||
|
//
|
||||||
|
PRWhen: when,
|
||||||
|
PRThen: then,
|
||||||
|
PRPriority: priority,
|
||||||
|
PRDisplay: display,
|
||||||
|
}
|
||||||
|
rc.SetTarget(display)
|
||||||
|
}
|
||||||
|
|
||||||
|
// mkPageRuleBlob creates the 1,301,when,then string used in displays.
|
||||||
|
func mkPageRuleBlob(priority int, code uint16, when, then string) string {
|
||||||
|
return fmt.Sprintf("%d,%03d,%s,%s", priority, code, when, then)
|
||||||
|
}
|
||||||
|
|
||||||
|
// makeSingleRedirectFromRawRec updates a RecordConfig to be a
|
||||||
|
// SINGLEREDIRECT using the data from a RawRecord.
|
||||||
|
func makeSingleRedirectFromRawRec(rc *models.RecordConfig, code uint16, name, when, then string) {
|
||||||
|
target := targetFromRaw(name, code, when, then)
|
||||||
|
|
||||||
|
rc.Type = SINGLEREDIRECT
|
||||||
|
rc.TTL = 1
|
||||||
|
rc.CloudflareRedirect = &models.CloudflareSingleRedirectConfig{
|
||||||
|
Code: code,
|
||||||
|
//
|
||||||
|
PRWhen: "UNKNOWABLE",
|
||||||
|
PRThen: "UNKNOWABLE",
|
||||||
|
PRPriority: 0,
|
||||||
|
PRDisplay: "UNKNOWABLE",
|
||||||
|
//
|
||||||
|
SRName: name,
|
||||||
|
SRWhen: when,
|
||||||
|
SRThen: then,
|
||||||
|
SRDisplay: target,
|
||||||
|
}
|
||||||
|
rc.SetTarget(rc.CloudflareRedirect.SRDisplay)
|
||||||
|
}
|
||||||
|
|
||||||
|
// targetFromRaw create the display text used for a normal Redirect.
|
||||||
|
func targetFromRaw(name string, code uint16, when, then string) string {
|
||||||
|
return fmt.Sprintf("%s code=(%03d) when=(%s) then=(%s)",
|
||||||
|
name,
|
||||||
|
code,
|
||||||
|
when,
|
||||||
|
then,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeSingleRedirectFromAPI updatese a RecordConfig to be a SINGLEREDIRECT using data downloaded via the API.
|
||||||
|
func MakeSingleRedirectFromAPI(rc *models.RecordConfig, code uint16, name, when, then string) {
|
||||||
|
// The target is the same as the name. It is the responsibility of the record creator to name it something diffable.
|
||||||
|
target := targetFromAPIData(name, code, when, then)
|
||||||
|
|
||||||
|
rc.Type = SINGLEREDIRECT
|
||||||
|
rc.TTL = 1
|
||||||
|
rc.CloudflareRedirect = &models.CloudflareSingleRedirectConfig{
|
||||||
|
Code: code,
|
||||||
|
//
|
||||||
|
PRWhen: "UNKNOWABLE",
|
||||||
|
PRThen: "UNKNOWABLE",
|
||||||
|
PRPriority: 0,
|
||||||
|
PRDisplay: "UNKNOWABLE",
|
||||||
|
//
|
||||||
|
SRName: name,
|
||||||
|
SRWhen: when,
|
||||||
|
SRThen: then,
|
||||||
|
SRDisplay: target,
|
||||||
|
}
|
||||||
|
rc.SetTarget(rc.CloudflareRedirect.SRDisplay)
|
||||||
|
}
|
||||||
|
|
||||||
|
// targetFromAPIData creates the display text used for a Redirect as received from Cloudflare's API.
|
||||||
|
func targetFromAPIData(name string, code uint16, when, then string) string {
|
||||||
|
return fmt.Sprintf("%s code=(%03d) when=(%s) then=(%s)",
|
||||||
|
name,
|
||||||
|
code,
|
||||||
|
when,
|
||||||
|
then,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// makeSingleRedirectFromConvert updates a RecordConfig to be a SINGLEREDIRECT using data from a PAGE_RULE conversion.
|
||||||
|
func makeSingleRedirectFromConvert(rc *models.RecordConfig,
|
||||||
|
priority int,
|
||||||
|
prWhen, prThen string,
|
||||||
|
code uint16,
|
||||||
|
srName, srWhen, srThen string) {
|
||||||
|
|
||||||
|
srDisplay := targetFromConverted(priority, code, prWhen, prThen, srWhen, srThen)
|
||||||
|
|
||||||
|
rc.Type = SINGLEREDIRECT
|
||||||
|
rc.TTL = 1
|
||||||
|
sr := rc.CloudflareRedirect
|
||||||
|
sr.Code = code
|
||||||
|
|
||||||
|
sr.SRName = srName
|
||||||
|
sr.SRWhen = srWhen
|
||||||
|
sr.SRThen = srThen
|
||||||
|
sr.SRDisplay = srDisplay
|
||||||
|
|
||||||
|
rc.SetTarget(rc.CloudflareRedirect.SRDisplay)
|
||||||
|
}
|
||||||
|
|
||||||
|
// targetFromConverted makes the display text used when a redirect was the result of converting a PAGE_RULE.
|
||||||
|
func targetFromConverted(prPriority int, code uint16, prWhen, prThen, srWhen, srThen string) string {
|
||||||
|
return fmt.Sprintf("%d,%03d,%s,%s code=(%03d) when=(%s) then=(%s)", prPriority, code, prWhen, prThen, code, srWhen, srThen)
|
||||||
|
}
|
|
@ -1,19 +0,0 @@
|
||||||
package cfsingleredirect
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/StackExchange/dnscontrol/v4/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
func FromAPIData(sm, sr string, code uint16) *models.CloudflareSingleRedirectConfig {
|
|
||||||
r := &models.CloudflareSingleRedirectConfig{
|
|
||||||
PRWhen: "UNKNOWABLE",
|
|
||||||
PRThen: "UNKNOWABLE",
|
|
||||||
Code: code,
|
|
||||||
SRDisplay: fmt.Sprintf("code=%03d when=(%v) then=(%v)", code, sm, sr),
|
|
||||||
SRWhen: sm,
|
|
||||||
SRThen: sr,
|
|
||||||
}
|
|
||||||
return r
|
|
||||||
}
|
|
Loading…
Reference in a new issue