mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2025-10-24 21:24:38 +08:00
NEW PROVIDER: ADGUARDHOME (#3638)
This commit is contained in:
parent
4ce19352e9
commit
e1830abb58
19 changed files with 637 additions and 6 deletions
|
|
@ -39,7 +39,7 @@ changelog:
|
||||||
regexp: "(?i)^.*(major|new provider|feature)[(\\w)]*:+.*$"
|
regexp: "(?i)^.*(major|new provider|feature)[(\\w)]*:+.*$"
|
||||||
order: 1
|
order: 1
|
||||||
- title: 'Provider-specific changes:'
|
- title: 'Provider-specific changes:'
|
||||||
regexp: "(?i)((akamaiedge|autodns|axfrd|azure|azure_private_dns|bind|bunnydns|cloudflare|cloudflareapi_old|cloudns|cnr|cscglobal|desec|digitalocean|dnsimple|dnsmadeeasy|doh|domainnameshop|dynadot|easyname|exoscale|fortigate|gandi|gcloud|gcore|hedns|hetzner|hexonet|hostingde|huaweicloud|inwx|linode|loopia|luadns|msdns|mythicbeasts|namecheap|namedotcom|netcup|netlify|ns1|opensrs|oracle|ovh|packetframe|porkbun|powerdns|realtimeregister|route53|rwth|sakuracloud|softlayer|transip|vultr).*:)+.*"
|
regexp: "(?i)((adguardhome|akamaiedge|autodns|axfrd|azure|azure_private_dns|bind|bunnydns|cloudflare|cloudflareapi_old|cloudns|cnr|cscglobal|desec|digitalocean|dnsimple|dnsmadeeasy|doh|domainnameshop|dynadot|easyname|exoscale|fortigate|gandi|gcloud|gcore|hedns|hetzner|hexonet|hostingde|huaweicloud|inwx|linode|loopia|luadns|msdns|mythicbeasts|namecheap|namedotcom|netcup|netlify|ns1|opensrs|oracle|ovh|packetframe|porkbun|powerdns|realtimeregister|route53|rwth|sakuracloud|softlayer|transip|vultr).*:)+.*"
|
||||||
order: 2
|
order: 2
|
||||||
- title: 'Documentation:'
|
- title: 'Documentation:'
|
||||||
regexp: "(?i)^.*(docs)[(\\w)]*:+.*$"
|
regexp: "(?i)^.*(docs)[(\\w)]*:+.*$"
|
||||||
|
|
|
||||||
1
OWNERS
1
OWNERS
|
|
@ -1,3 +1,4 @@
|
||||||
|
providers/adguardhome @ishanjain28
|
||||||
providers/akamaiedgedns @edglynes
|
providers/akamaiedgedns @edglynes
|
||||||
providers/autodns @arnoschoon
|
providers/autodns @arnoschoon
|
||||||
providers/axfrddns @hnrgrgr
|
providers/axfrddns @hnrgrgr
|
||||||
|
|
|
||||||
38
commands/types/dnscontrol.d.ts
vendored
38
commands/types/dnscontrol.d.ts
vendored
|
|
@ -220,6 +220,44 @@ declare function A(name: string, address: string | number, ...modifiers: RecordM
|
||||||
*/
|
*/
|
||||||
declare function AAAA(name: string, address: string, ...modifiers: RecordModifier[]): DomainModifier;
|
declare function AAAA(name: string, address: string, ...modifiers: RecordModifier[]): DomainModifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `ADGUARDHOME_AAAA_PASSTHROUGH` represents the literal 'A'. AdGuardHome uses this to passthrough
|
||||||
|
* the original values of a record type.
|
||||||
|
*
|
||||||
|
* The second argument to this record type must be empty.
|
||||||
|
*
|
||||||
|
* See [this](https://github.com/AdguardTeam/Adguardhome/wiki/Configuration) page for
|
||||||
|
* more information.
|
||||||
|
*
|
||||||
|
* ```javascript
|
||||||
|
* D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER),
|
||||||
|
* ADGUARDHOME_AAAA_PASSTHROUGH("foo", ""),
|
||||||
|
* );
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @see https://docs.dnscontrol.org/language-reference/domain-modifiers/service-provider-specific//adguardhome_aaaa_passthrough
|
||||||
|
*/
|
||||||
|
declare function ADGUARDHOME_AAAA_PASSTHROUGH(source: string, destination: string): DomainModifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `ADGUARDHOME_A_PASSTHROUGH` represents the literal 'A'. AdGuardHome uses this to passthrough
|
||||||
|
* the original values of a record type.
|
||||||
|
*
|
||||||
|
* The second argument to this record type must be empty.
|
||||||
|
*
|
||||||
|
* See [this](https://github.com/AdguardTeam/Adguardhome/wiki/Configuration) page for
|
||||||
|
* more information.
|
||||||
|
*
|
||||||
|
* ```javascript
|
||||||
|
* D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER),
|
||||||
|
* ADGUARDHOME_A_PASSTHROUGH("foo", ""),
|
||||||
|
* );
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @see https://docs.dnscontrol.org/language-reference/domain-modifiers/service-provider-specific//adguardhome_a_passthrough
|
||||||
|
*/
|
||||||
|
declare function ADGUARDHOME_A_PASSTHROUGH(source: string, destination: string): DomainModifier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AKAMAICDN is a proprietary record type that is used to configure [Zone Apex Mapping](https://www.akamai.com/blog/security/edge-dns--zone-apex-mapping---dnssec).
|
* AKAMAICDN is a proprietary record type that is used to configure [Zone Apex Mapping](https://www.akamai.com/blog/security/edge-dns--zone-apex-mapping---dnssec).
|
||||||
* The AKAMAICDN target must be preconfigured in the Akamai network.
|
* The AKAMAICDN target must be preconfigured in the Akamai network.
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,9 @@
|
||||||
* [URL](language-reference/domain-modifiers/URL.md)
|
* [URL](language-reference/domain-modifiers/URL.md)
|
||||||
* [URL301](language-reference/domain-modifiers/URL301.md)
|
* [URL301](language-reference/domain-modifiers/URL301.md)
|
||||||
* Service Provider specific
|
* Service Provider specific
|
||||||
|
* AdGuard Home
|
||||||
|
* [ADGUARDHOME_A_PASSTHROUGH](language-reference/domain-modifiers/ADGUARDHOME_A_PASSTHROUGH.md)
|
||||||
|
* [ADGUARDHOME_AAAA_PASSTHROUGH](language-reference/domain-modifiers/ADGUARDHOME_AAAA_PASSTHROUGH.md)
|
||||||
* Akamai Edge Dns
|
* Akamai Edge Dns
|
||||||
* [AKAMAICDN](language-reference/domain-modifiers/AKAMAICDN.md)
|
* [AKAMAICDN](language-reference/domain-modifiers/AKAMAICDN.md)
|
||||||
* Amazon Route 53
|
* Amazon Route 53
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
---
|
||||||
|
name: ADGUARDHOME_AAAA_PASSTHROUGH
|
||||||
|
parameters:
|
||||||
|
- source
|
||||||
|
- destination
|
||||||
|
provider: ADGUARDHOME
|
||||||
|
parameter_types:
|
||||||
|
source: string
|
||||||
|
destination: string
|
||||||
|
---
|
||||||
|
|
||||||
|
`ADGUARDHOME_AAAA_PASSTHROUGH` represents the literal 'A'. AdGuardHome uses this to passthrough
|
||||||
|
the original values of a record type.
|
||||||
|
|
||||||
|
The second argument to this record type must be empty.
|
||||||
|
|
||||||
|
See [this](https://github.com/AdguardTeam/Adguardhome/wiki/Configuration) page for
|
||||||
|
more information.
|
||||||
|
|
||||||
|
{% code title="dnsconfig.js" %}
|
||||||
|
```javascript
|
||||||
|
D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER),
|
||||||
|
ADGUARDHOME_AAAA_PASSTHROUGH("foo", ""),
|
||||||
|
);
|
||||||
|
```
|
||||||
|
{% endcode %}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
---
|
||||||
|
name: ADGUARDHOME_A_PASSTHROUGH
|
||||||
|
parameters:
|
||||||
|
- source
|
||||||
|
- destination
|
||||||
|
provider: ADGUARDHOME
|
||||||
|
parameter_types:
|
||||||
|
source: string
|
||||||
|
destination: string
|
||||||
|
---
|
||||||
|
|
||||||
|
`ADGUARDHOME_A_PASSTHROUGH` represents the literal 'A'. AdGuardHome uses this to passthrough
|
||||||
|
the original values of a record type.
|
||||||
|
|
||||||
|
The second argument to this record type must be empty.
|
||||||
|
|
||||||
|
See [this](https://github.com/AdguardTeam/Adguardhome/wiki/Configuration) page for
|
||||||
|
more information.
|
||||||
|
|
||||||
|
{% code title="dnsconfig.js" %}
|
||||||
|
```javascript
|
||||||
|
D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER),
|
||||||
|
ADGUARDHOME_A_PASSTHROUGH("foo", ""),
|
||||||
|
);
|
||||||
|
```
|
||||||
|
{% endcode %}
|
||||||
57
documentation/provider/adguardhome.md
Normal file
57
documentation/provider/adguardhome.md
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
This is the provider for [AdGuardHome](https://github.com/AdguardTeam/AdGuardHome).
|
||||||
|
|
||||||
|
## Important notes
|
||||||
|
|
||||||
|
This provider only supports the following record types.
|
||||||
|
|
||||||
|
* A
|
||||||
|
* AAAA
|
||||||
|
* CNAME
|
||||||
|
* ALIAS
|
||||||
|
* ADGUARDHOME_A_PASSTHROUGH
|
||||||
|
* ADGUARDHOME_AAAA_PASSTHROUGH
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
To use this provider, add an entry to `creds.json` with `TYPE` set to `ADGUARDHOME`.
|
||||||
|
|
||||||
|
Required fields include:
|
||||||
|
|
||||||
|
* `username` and `password`: Authentication information
|
||||||
|
* `host`: The hostname/address of AdGuard Home instance
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
{% code title="creds.json" %}
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"adguard_home": {
|
||||||
|
"TYPE": "ADGUARDHOME",
|
||||||
|
"username": "admin",
|
||||||
|
"password": "your-password",
|
||||||
|
"host": "https://foo.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
{% endcode %}
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
An example configuration:
|
||||||
|
|
||||||
|
{% code title="dnsconfig.js" %}
|
||||||
|
```javascript
|
||||||
|
var REG_NONE = NewRegistrar("none");
|
||||||
|
var DSP_ADGUARDHOME = NewDnsProvider("adguard_home");
|
||||||
|
|
||||||
|
// Example domain where the CF proxy abides by the default (off).
|
||||||
|
D("example.com", REG_NONE, DnsProvider(DSP_ADGUARDHOME),
|
||||||
|
A("foo", "1.2.3.4"),
|
||||||
|
AAAA("another", "2003::1"),
|
||||||
|
ALIAS("@", "www.example.com."),
|
||||||
|
CNAME("myalias", "www.example.com."),
|
||||||
|
ADGUARDHOME_A_PASSTHROUGH("abc", ""),
|
||||||
|
ADGUARDHOME_AAAA_PASSTHROUGH("abc", ""),
|
||||||
|
);
|
||||||
|
```
|
||||||
|
{% endcode %}
|
||||||
|
|
||||||
|
|
@ -25,6 +25,7 @@ Jump to a table:
|
||||||
|
|
||||||
| Provider name | Official Support | DNS Provider | Registrar |
|
| Provider name | Official Support | DNS Provider | Registrar |
|
||||||
| ------------- | ---------------- | ------------ | --------- |
|
| ------------- | ---------------- | ------------ | --------- |
|
||||||
|
| [`ADGUARDHOME`](adguardhome.md) | ❌ | ✅ | ❌ |
|
||||||
| [`AKAMAIEDGEDNS`](akamaiedgedns.md) | ❌ | ✅ | ❌ |
|
| [`AKAMAIEDGEDNS`](akamaiedgedns.md) | ❌ | ✅ | ❌ |
|
||||||
| [`AUTODNS`](autodns.md) | ❌ | ✅ | ✅ |
|
| [`AUTODNS`](autodns.md) | ❌ | ✅ | ✅ |
|
||||||
| [`AXFRDDNS`](axfrddns.md) | ❌ | ✅ | ❌ |
|
| [`AXFRDDNS`](axfrddns.md) | ❌ | ✅ | ❌ |
|
||||||
|
|
@ -85,6 +86,7 @@ Jump to a table:
|
||||||
|
|
||||||
| Provider name | [Concurrency Verified](../advanced-features/concurrency-verified.md) | [dual host](../advanced-features/dual-host.md) | create-domains | get-zones |
|
| Provider name | [Concurrency Verified](../advanced-features/concurrency-verified.md) | [dual host](../advanced-features/dual-host.md) | create-domains | get-zones |
|
||||||
| ------------- | -------------------------------------------------------------------- | ---------------------------------------------- | -------------- | --------- |
|
| ------------- | -------------------------------------------------------------------- | ---------------------------------------------- | -------------- | --------- |
|
||||||
|
| [`ADGUARDHOME`](adguardhome.md) | ❔ | ❔ | ❌ | ❌ |
|
||||||
| [`AKAMAIEDGEDNS`](akamaiedgedns.md) | ❔ | ✅ | ✅ | ✅ |
|
| [`AKAMAIEDGEDNS`](akamaiedgedns.md) | ❔ | ✅ | ✅ | ✅ |
|
||||||
| [`AUTODNS`](autodns.md) | ✅ | ❌ | ❌ | ✅ |
|
| [`AUTODNS`](autodns.md) | ✅ | ❌ | ❌ | ✅ |
|
||||||
| [`AXFRDDNS`](axfrddns.md) | ✅ | ❌ | ❌ | ❌ |
|
| [`AXFRDDNS`](axfrddns.md) | ✅ | ❌ | ❌ | ❌ |
|
||||||
|
|
@ -144,6 +146,7 @@ Jump to a table:
|
||||||
|
|
||||||
| Provider name | [`ALIAS`](../language-reference/domain-modifiers/ALIAS.md) | [`DNAME`](../language-reference/domain-modifiers/DNAME.md) | [`LOC`](../language-reference/domain-modifiers/LOC.md) | [`PTR`](../language-reference/domain-modifiers/PTR.md) | [`SOA`](../language-reference/domain-modifiers/SOA.md) |
|
| Provider name | [`ALIAS`](../language-reference/domain-modifiers/ALIAS.md) | [`DNAME`](../language-reference/domain-modifiers/DNAME.md) | [`LOC`](../language-reference/domain-modifiers/LOC.md) | [`PTR`](../language-reference/domain-modifiers/PTR.md) | [`SOA`](../language-reference/domain-modifiers/SOA.md) |
|
||||||
| ------------- | ---------------------------------------------------------- | ---------------------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------ | ------------------------------------------------------ |
|
| ------------- | ---------------------------------------------------------- | ---------------------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------ | ------------------------------------------------------ |
|
||||||
|
| [`ADGUARDHOME`](adguardhome.md) | ✅ | ❔ | ❔ | ❔ | ❔ |
|
||||||
| [`AKAMAIEDGEDNS`](akamaiedgedns.md) | ❌ | ❔ | ✅ | ✅ | ❌ |
|
| [`AKAMAIEDGEDNS`](akamaiedgedns.md) | ❌ | ❔ | ✅ | ✅ | ❌ |
|
||||||
| [`AUTODNS`](autodns.md) | ✅ | ❔ | ❔ | ✅ | ❔ |
|
| [`AUTODNS`](autodns.md) | ✅ | ❔ | ❔ | ✅ | ❔ |
|
||||||
| [`AXFRDDNS`](axfrddns.md) | ❌ | ✅ | ✅ | ✅ | ❌ |
|
| [`AXFRDDNS`](axfrddns.md) | ❌ | ✅ | ✅ | ✅ | ❌ |
|
||||||
|
|
|
||||||
|
|
@ -359,6 +359,16 @@ func cfRedirTemp(pattern, target string) *models.RecordConfig {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func aghAPassthrough(pattern, target string) *models.RecordConfig {
|
||||||
|
r := makeRec(pattern, target, "ADGUARDHOME_A_PASSTHROUGH")
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func aghAAAAPassthrough(pattern, target string) *models.RecordConfig {
|
||||||
|
r := makeRec(pattern, target, "ADGUARDHOME_AAAA_PASSTHROUGH")
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
func cname(name, target string) *models.RecordConfig {
|
func cname(name, target string) *models.RecordConfig {
|
||||||
return makeRec(name, target, "CNAME")
|
return makeRec(name, target, "CNAME")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1316,6 +1316,16 @@ func makeTests() []*TestGroup {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
testgroup("ADGUARDHOME_A_PASSTHROUGH",
|
||||||
|
only("ADGUARDHOME"),
|
||||||
|
tc("simple", aghAPassthrough("foo", "")),
|
||||||
|
),
|
||||||
|
|
||||||
|
testgroup("ADGUARDHOME_AAAA_PASSTHROUGH",
|
||||||
|
only("ADGUARDHOME"),
|
||||||
|
tc("simple", aghAAAAPassthrough("foo", "")),
|
||||||
|
),
|
||||||
|
|
||||||
//// IGNORE* features
|
//// IGNORE* features
|
||||||
|
|
||||||
// Narrative: You're basically done now. These remaining tests
|
// Narrative: You're basically done now. These remaining tests
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,11 @@
|
||||||
{
|
{
|
||||||
|
"ADGUARDHOME": {
|
||||||
|
"TYPE": "ADGUARDHOME",
|
||||||
|
"username": "$ADGUARDHOME_USERNAME",
|
||||||
|
"password": "$ADGUARDHOME_PASSWORD",
|
||||||
|
"host": "$ADGUARDHOME_HOST",
|
||||||
|
"domain": "$ADGUARDHOME_DOMAIN"
|
||||||
|
},
|
||||||
"AKAMAIEDGEDNS": {
|
"AKAMAIEDGEDNS": {
|
||||||
"TYPE": "AKAMAIEDGEDNS",
|
"TYPE": "AKAMAIEDGEDNS",
|
||||||
"access_token": "$AED_ACCESS_TOKEN",
|
"access_token": "$AED_ACCESS_TOKEN",
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@ func (dc *DomainConfig) Punycode() error {
|
||||||
if err := rec.SetTarget(t); err != nil {
|
if err := rec.SetTarget(t); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case "CLOUDFLAREAPI_SINGLE_REDIRECT", "CF_REDIRECT", "CF_TEMP_REDIRECT", "CF_WORKER_ROUTE":
|
case "CLOUDFLAREAPI_SINGLE_REDIRECT", "CF_REDIRECT", "CF_TEMP_REDIRECT", "CF_WORKER_ROUTE", "ADGUARDHOME_A_PASSTHROUGH", "ADGUARDHOME_AAAA_PASSTHROUGH":
|
||||||
if err := rec.SetTarget(rec.GetTargetField()); err != nil {
|
if err := rec.SetTarget(rec.GetTargetField()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -619,7 +619,7 @@ func Downcase(recs []*RecordConfig) {
|
||||||
// Target is case insensitive. Downcase it.
|
// Target is case insensitive. Downcase it.
|
||||||
r.target = strings.ToLower(r.target)
|
r.target = strings.ToLower(r.target)
|
||||||
// BUGFIX(tlim): isn't ALIAS in the wrong case statement?
|
// BUGFIX(tlim): isn't ALIAS in the wrong case statement?
|
||||||
case "A", "CAA", "CLOUDFLAREAPI_SINGLE_REDIRECT", "CF_REDIRECT", "CF_TEMP_REDIRECT", "CF_WORKER_ROUTE", "DHCID", "IMPORT_TRANSFORM", "LOC", "SSHFP", "TXT":
|
case "A", "CAA", "CLOUDFLAREAPI_SINGLE_REDIRECT", "CF_REDIRECT", "CF_TEMP_REDIRECT", "CF_WORKER_ROUTE", "DHCID", "IMPORT_TRANSFORM", "LOC", "SSHFP", "TXT", "ADGUARDHOME_A_PASSTHROUGH", "ADGUARDHOME_AAAA_PASSTHROUGH":
|
||||||
// Do nothing. (IP address or case sensitive target)
|
// Do nothing. (IP address or case sensitive target)
|
||||||
case "SOA":
|
case "SOA":
|
||||||
if r.target != "DEFAULT_NOT_SET." {
|
if r.target != "DEFAULT_NOT_SET." {
|
||||||
|
|
@ -643,7 +643,7 @@ func CanonicalizeTargets(recs []*RecordConfig, origin string) {
|
||||||
case "ALIAS", "ANAME", "CNAME", "DNAME", "DS", "DNSKEY", "MX", "NS", "NAPTR", "PTR", "SRV":
|
case "ALIAS", "ANAME", "CNAME", "DNAME", "DS", "DNSKEY", "MX", "NS", "NAPTR", "PTR", "SRV":
|
||||||
// Target is a hostname that might be a shortname. Turn it into a FQDN.
|
// Target is a hostname that might be a shortname. Turn it into a FQDN.
|
||||||
r.target = dnsutil.AddOrigin(r.target, originFQDN)
|
r.target = dnsutil.AddOrigin(r.target, originFQDN)
|
||||||
case "A", "AKAMAICDN", "CAA", "DHCID", "CLOUDFLAREAPI_SINGLE_REDIRECT", "CF_REDIRECT", "CF_TEMP_REDIRECT", "CF_WORKER_ROUTE", "HTTPS", "IMPORT_TRANSFORM", "LOC", "SSHFP", "SVCB", "TLSA", "TXT":
|
case "A", "AKAMAICDN", "CAA", "DHCID", "CLOUDFLAREAPI_SINGLE_REDIRECT", "CF_REDIRECT", "CF_TEMP_REDIRECT", "CF_WORKER_ROUTE", "HTTPS", "IMPORT_TRANSFORM", "LOC", "SSHFP", "SVCB", "TLSA", "TXT", "ADGUARDHOME_A_PASSTHROUGH", "ADGUARDHOME_AAAA_PASSTHROUGH":
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
case "SOA":
|
case "SOA":
|
||||||
if r.target != "DEFAULT_NOT_SET." {
|
if r.target != "DEFAULT_NOT_SET." {
|
||||||
|
|
|
||||||
|
|
@ -1262,7 +1262,9 @@ function recordBuilder(type, opts) {
|
||||||
record.type != 'CF_SINGLE_REDIRECT' &&
|
record.type != 'CF_SINGLE_REDIRECT' &&
|
||||||
record.type != 'CF_REDIRECT' &&
|
record.type != 'CF_REDIRECT' &&
|
||||||
record.type != 'CF_TEMP_REDIRECT' &&
|
record.type != 'CF_TEMP_REDIRECT' &&
|
||||||
record.type != 'CF_WORKER_ROUTE'
|
record.type != 'CF_WORKER_ROUTE' &&
|
||||||
|
record.type != "ADGUARDHOME_A_PASSTHROUGH" &&
|
||||||
|
record.type != "ADGUARDHOME_AAAA_PASSTHROUGH"
|
||||||
) {
|
) {
|
||||||
record.subdomain = d.subdomain;
|
record.subdomain = d.subdomain;
|
||||||
|
|
||||||
|
|
@ -1430,6 +1432,10 @@ var CF_WORKER_ROUTE = recordBuilder('CF_WORKER_ROUTE', {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var ADGUARDHOME_A_PASSTHROUGH = recordBuilder('ADGUARDHOME_A_PASSTHROUGH');
|
||||||
|
|
||||||
|
var ADGUARDHOME_AAAA_PASSTHROUGH = recordBuilder('ADGUARDHOME_AAAA_PASSTHROUGH');
|
||||||
|
|
||||||
var URL = recordBuilder('URL');
|
var URL = recordBuilder('URL');
|
||||||
var URL301 = recordBuilder('URL301');
|
var URL301 = recordBuilder('URL301');
|
||||||
var FRAME = recordBuilder('FRAME');
|
var FRAME = recordBuilder('FRAME');
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ func TestParsedFiles(t *testing.T) {
|
||||||
} else {
|
} else {
|
||||||
zoneFile = filepath.Join(testDir, testName, dc.Name+".zone")
|
zoneFile = filepath.Join(testDir, testName, dc.Name+".zone")
|
||||||
}
|
}
|
||||||
//fmt.Printf("DEBUG: zonefile = %q\n", zoneFile)
|
// fmt.Printf("DEBUG: zonefile = %q\n", zoneFile)
|
||||||
expectedZone, err := os.ReadFile(zoneFile)
|
expectedZone, err := os.ReadFile(zoneFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
|
|
@ -161,6 +161,8 @@ func TestErrors(t *testing.T) {
|
||||||
{"CF_REDIRECT With comma", `D("foo.com","reg",CF_REDIRECT("foo.com,","baaa"))`},
|
{"CF_REDIRECT With comma", `D("foo.com","reg",CF_REDIRECT("foo.com,","baaa"))`},
|
||||||
{"CF_TEMP_REDIRECT With comma", `D("foo.com","reg",CF_TEMP_REDIRECT("foo.com","baa,a"))`},
|
{"CF_TEMP_REDIRECT With comma", `D("foo.com","reg",CF_TEMP_REDIRECT("foo.com","baa,a"))`},
|
||||||
{"CF_WORKER_ROUTE With comma", `D("foo.com","reg",CF_WORKER_ROUTE("foo.com","baa,a"))`},
|
{"CF_WORKER_ROUTE With comma", `D("foo.com","reg",CF_WORKER_ROUTE("foo.com","baa,a"))`},
|
||||||
|
{"ADGUARDHOME_A_PASSTHROUGH With non-empty value", `D("foo.com","reg",ADGUARDHOME_A_PASSTHROUGH("foo","baaa"))`},
|
||||||
|
{"ADGUARDHOME_AAAA_PASSTHROUGH With non-empty value", `D("foo.com","reg",ADGUARDHOME_AAAA_PASSTHROUGH("foo,","baaa"))`},
|
||||||
{"Bad cidr", `D(reverse("foo.com"), "reg")`},
|
{"Bad cidr", `D(reverse("foo.com"), "reg")`},
|
||||||
{"Dup domains", `D("example.org", "reg"); D("example.org", "reg")`},
|
{"Dup domains", `D("example.org", "reg"); D("example.org", "reg")`},
|
||||||
{"Bad NAMESERVER", `D("example.com","reg", NAMESERVER("@","ns1.foo.com."))`},
|
{"Bad NAMESERVER", `D("example.com","reg", NAMESERVER("@","ns1.foo.com."))`},
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package all
|
||||||
|
|
||||||
import (
|
import (
|
||||||
// Define all known providers here. They should each register themselves with the providers package via init function.
|
// Define all known providers here. They should each register themselves with the providers package via init function.
|
||||||
|
_ "github.com/StackExchange/dnscontrol/v4/providers/adguardhome"
|
||||||
_ "github.com/StackExchange/dnscontrol/v4/providers/akamaiedgedns"
|
_ "github.com/StackExchange/dnscontrol/v4/providers/akamaiedgedns"
|
||||||
_ "github.com/StackExchange/dnscontrol/v4/providers/autodns"
|
_ "github.com/StackExchange/dnscontrol/v4/providers/autodns"
|
||||||
_ "github.com/StackExchange/dnscontrol/v4/providers/axfrddns"
|
_ "github.com/StackExchange/dnscontrol/v4/providers/axfrddns"
|
||||||
|
|
|
||||||
216
providers/adguardhome/adguardHomeProvider.go
Normal file
216
providers/adguardhome/adguardHomeProvider.go
Normal file
|
|
@ -0,0 +1,216 @@
|
||||||
|
package adguardhome
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/StackExchange/dnscontrol/v4/models"
|
||||||
|
"github.com/StackExchange/dnscontrol/v4/pkg/diff2"
|
||||||
|
"github.com/StackExchange/dnscontrol/v4/pkg/printer"
|
||||||
|
"github.com/StackExchange/dnscontrol/v4/providers"
|
||||||
|
"github.com/miekg/dns/dnsutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newDsp(conf map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) {
|
||||||
|
return newAdguardHome(conf, metadata)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newAdguardHome creates the provider.
|
||||||
|
func newAdguardHome(m map[string]string, _ json.RawMessage) (*adguardHomeProvider, error) {
|
||||||
|
c := &adguardHomeProvider{}
|
||||||
|
|
||||||
|
c.username, c.password, c.host = m["username"], m["password"], m["host"]
|
||||||
|
|
||||||
|
if c.username == "" {
|
||||||
|
return nil, errors.New("missing adguard home username")
|
||||||
|
}
|
||||||
|
if c.password == "" {
|
||||||
|
return nil, errors.New("missing adguard home password")
|
||||||
|
}
|
||||||
|
if c.host == "" {
|
||||||
|
return nil, errors.New("missing adguard home endpoint")
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var features = providers.DocumentationNotes{
|
||||||
|
providers.CanConcur: providers.Unimplemented(),
|
||||||
|
providers.CanUseAlias: providers.Can(),
|
||||||
|
providers.CanGetZones: providers.Cannot(),
|
||||||
|
providers.DocOfficiallySupported: providers.Cannot(),
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
const providerName = "ADGUARDHOME"
|
||||||
|
const providerMaintainer = "@ishanjain28"
|
||||||
|
fns := providers.DspFuncs{
|
||||||
|
Initializer: newDsp,
|
||||||
|
RecordAuditor: AuditRecords,
|
||||||
|
}
|
||||||
|
providers.RegisterCustomRecordType("ADGUARDHOME_A_PASSTHROUGH", providerName, "")
|
||||||
|
providers.RegisterCustomRecordType("ADGUARDHOME_AAAA_PASSTHROUGH", providerName, "")
|
||||||
|
providers.RegisterDomainServiceProviderType(providerName, fns, features)
|
||||||
|
providers.RegisterMaintainer(providerName, providerMaintainer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNameservers returns the nameservers for a domain.
|
||||||
|
func (c *adguardHomeProvider) GetNameservers(domain string) ([]*models.Nameserver, error) {
|
||||||
|
return []*models.Nameserver{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||||
|
func (c *adguardHomeProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, int, error) {
|
||||||
|
// TTLs don't matter in ADGUARDHOME and
|
||||||
|
// we use the default value of 300
|
||||||
|
for _, record := range dc.Records {
|
||||||
|
record.TTL = 300
|
||||||
|
}
|
||||||
|
|
||||||
|
var corrections []*models.Correction
|
||||||
|
|
||||||
|
changes, actualChangeCount, err := diff2.ByRecord(existingRecords, dc,
|
||||||
|
func(rec *models.RecordConfig) string { return "" },
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
for _, change := range changes {
|
||||||
|
var corr *models.Correction
|
||||||
|
switch change.Type {
|
||||||
|
case diff2.REPORT:
|
||||||
|
printer.Warnf("diff2 report message\n")
|
||||||
|
corr = &models.Correction{Msg: change.MsgsJoined}
|
||||||
|
case diff2.CREATE:
|
||||||
|
re, err := toRewriteEntry(dc.Name, change.New[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
corr = &models.Correction{
|
||||||
|
Msg: change.Msgs[0],
|
||||||
|
F: func() error {
|
||||||
|
return c.createRecord(re)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
case diff2.CHANGE:
|
||||||
|
oldRe, err := toRewriteEntry(dc.Name, change.Old[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
newRe, err := toRewriteEntry(dc.Name, change.New[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
corr = &models.Correction{
|
||||||
|
Msg: change.Msgs[0],
|
||||||
|
F: func() error {
|
||||||
|
return c.modifyRecord(oldRe, newRe)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
case diff2.DELETE:
|
||||||
|
re, err := toRewriteEntry(dc.Name, change.Old[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
corr = &models.Correction{
|
||||||
|
Msg: change.Msgs[0],
|
||||||
|
F: func() error {
|
||||||
|
return c.deleteRecord(re)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unhandled change.Type %s", change.Type))
|
||||||
|
}
|
||||||
|
|
||||||
|
corrections = append(corrections, corr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return corrections, actualChangeCount, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetZoneRecords gets the records of a zone and returns them in RecordConfig format.
|
||||||
|
func (c *adguardHomeProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) {
|
||||||
|
records, err := c.getRecords(domain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
existingRecords := make([]*models.RecordConfig, 0, len(records))
|
||||||
|
for _, r := range records {
|
||||||
|
newRec, err := toRc(domain, r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
existingRecords = append(existingRecords, newRec)
|
||||||
|
}
|
||||||
|
|
||||||
|
return existingRecords, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func toRewriteEntry(domain string, rc *models.RecordConfig) (rewriteEntry, error) {
|
||||||
|
re := rewriteEntry{
|
||||||
|
Domain: rc.NameFQDN,
|
||||||
|
}
|
||||||
|
switch rc.Type {
|
||||||
|
case "A", "AAAA":
|
||||||
|
re.Answer = rc.GetTargetIP().String()
|
||||||
|
|
||||||
|
case "CNAME", "ALIAS":
|
||||||
|
re.Answer = rc.GetTargetField()
|
||||||
|
re.Answer = dnsutil.TrimDomainName(re.Answer, domain)
|
||||||
|
|
||||||
|
case "ADGUARDHOME_A_PASSTHROUGH":
|
||||||
|
re.Answer = "A"
|
||||||
|
|
||||||
|
case "ADGUARDHOME_AAAA_PASSTHROUGH":
|
||||||
|
re.Answer = "AAAA"
|
||||||
|
|
||||||
|
default:
|
||||||
|
return re, fmt.Errorf("rtype %s is not supported", rc.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
return re, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func toRc(domain string, r rewriteEntry) (*models.RecordConfig, error) {
|
||||||
|
rc := &models.RecordConfig{
|
||||||
|
TTL: 300,
|
||||||
|
Original: r,
|
||||||
|
}
|
||||||
|
rc.SetLabelFromFQDN(r.Domain, domain)
|
||||||
|
|
||||||
|
addr := net.ParseIP(r.Answer)
|
||||||
|
if addr != nil {
|
||||||
|
rc.SetTargetIP(addr)
|
||||||
|
if addr.To4() != nil {
|
||||||
|
rc.Type = "A"
|
||||||
|
} else {
|
||||||
|
rc.Type = "AAAA"
|
||||||
|
}
|
||||||
|
} else if r.Answer == "A" {
|
||||||
|
rc.Type = "ADGUARDHOME_A_PASSTHROUGH"
|
||||||
|
} else if r.Answer == "AAAA" {
|
||||||
|
rc.Type = "ADGUARDHOME_AAAA_PASSTHROUGH"
|
||||||
|
} else {
|
||||||
|
answer := dnsutil.TrimDomainName(r.Answer, domain)
|
||||||
|
rc.SetTarget(answer)
|
||||||
|
|
||||||
|
if r.Domain == domain {
|
||||||
|
rc.Type = "ALIAS"
|
||||||
|
} else {
|
||||||
|
rc.Type = "CNAME"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc.Type == "ADGUARDHOME_A_PASSTHROUGH" && r.Answer != "A") ||
|
||||||
|
(rc.Type == "ADGUARDHOME_AAAA_PASSTHROUGH" && r.Answer != "AAAA") {
|
||||||
|
return rc, errors.New("found invalid values for ADGUARDHOME_A_PASSTHROUGH or ADGUARDHOME_AAAA_PASSTHROUGH record")
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc, nil
|
||||||
|
}
|
||||||
176
providers/adguardhome/api.go
Normal file
176
providers/adguardhome/api.go
Normal file
|
|
@ -0,0 +1,176 @@
|
||||||
|
package adguardhome
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/StackExchange/dnscontrol/v4/pkg/printer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type adguardHomeProvider struct {
|
||||||
|
username string
|
||||||
|
password string
|
||||||
|
host string
|
||||||
|
}
|
||||||
|
|
||||||
|
type requestParams map[string]any
|
||||||
|
|
||||||
|
type errorResponse struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type rewriteEntry struct {
|
||||||
|
Domain string `json:"domain"`
|
||||||
|
Answer string `json:"answer"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *adguardHomeProvider) write(method, endpoint string, params requestParams) ([]byte, error) {
|
||||||
|
authHeader := "Basic " + base64.StdEncoding.EncodeToString([]byte(c.username+":"+c.password))
|
||||||
|
|
||||||
|
reqBodyJSON, err := json.Marshal(params)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
client := &http.Client{}
|
||||||
|
req, _ := http.NewRequest(method, c.host+endpoint, bytes.NewBuffer(reqBodyJSON))
|
||||||
|
req.Header.Add("Authorization", authHeader)
|
||||||
|
req.Header.Add("Content-Type", "application/json")
|
||||||
|
|
||||||
|
retrycnt := 0
|
||||||
|
|
||||||
|
retry:
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyString, _ := io.ReadAll(resp.Body)
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusTooManyRequests || resp.StatusCode == http.StatusServiceUnavailable {
|
||||||
|
retrycnt++
|
||||||
|
if retrycnt == 5 {
|
||||||
|
return bodyString, errors.New("rate limit exceeded")
|
||||||
|
}
|
||||||
|
printer.Warnf("rate limiting.. waiting for %d second(s)\n", retrycnt*10)
|
||||||
|
time.Sleep(time.Second * time.Duration(retrycnt*10))
|
||||||
|
goto retry
|
||||||
|
}
|
||||||
|
|
||||||
|
var errResp errorResponse
|
||||||
|
err = json.Unmarshal(bodyString, &errResp)
|
||||||
|
if err == nil {
|
||||||
|
return bodyString, fmt.Errorf("AdguardHome API error: %s URL:%s%s ", errResp.Message, req.Host, req.URL.RequestURI())
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusOK {
|
||||||
|
return bodyString, nil
|
||||||
|
} else {
|
||||||
|
return nil, errors.New(string(bodyString))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *adguardHomeProvider) get(endpoint string) ([]byte, error) {
|
||||||
|
authHeader := "Basic " + base64.StdEncoding.EncodeToString([]byte(c.username+":"+c.password))
|
||||||
|
|
||||||
|
client := &http.Client{}
|
||||||
|
req, _ := http.NewRequest(http.MethodGet, c.host+endpoint, nil)
|
||||||
|
req.Header.Add("Authorization", authHeader)
|
||||||
|
|
||||||
|
retrycnt := 0
|
||||||
|
|
||||||
|
retry:
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyString, _ := io.ReadAll(resp.Body)
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusTooManyRequests || resp.StatusCode == http.StatusServiceUnavailable {
|
||||||
|
retrycnt++
|
||||||
|
if retrycnt == 5 {
|
||||||
|
return bodyString, errors.New("rate limit exceeded")
|
||||||
|
}
|
||||||
|
printer.Warnf("rate limiting.. waiting for %d second(s)\n", retrycnt*10)
|
||||||
|
time.Sleep(time.Second * time.Duration(retrycnt*10))
|
||||||
|
goto retry
|
||||||
|
}
|
||||||
|
|
||||||
|
var errResp errorResponse
|
||||||
|
err = json.Unmarshal(bodyString, &errResp)
|
||||||
|
if err == nil {
|
||||||
|
return bodyString, fmt.Errorf("AdguardHome API error: %s URL:%s%s ", errResp.Message, req.Host, req.URL.RequestURI())
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusOK {
|
||||||
|
return bodyString, nil
|
||||||
|
} else {
|
||||||
|
return nil, errors.New(string(bodyString))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *adguardHomeProvider) createRecord(r rewriteEntry) error {
|
||||||
|
rec := requestParams{
|
||||||
|
"domain": r.Domain,
|
||||||
|
"answer": r.Answer,
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.write(http.MethodPost, "/control/rewrite/add", rec); err != nil {
|
||||||
|
return fmt.Errorf("failed to create record (adguard home): %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *adguardHomeProvider) deleteRecord(r rewriteEntry) error {
|
||||||
|
rec := requestParams{
|
||||||
|
"domain": r.Domain,
|
||||||
|
"answer": r.Answer,
|
||||||
|
}
|
||||||
|
if _, err := c.write(http.MethodPost, "/control/rewrite/delete", rec); err != nil {
|
||||||
|
return fmt.Errorf("failed to delete record (adguard home): %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *adguardHomeProvider) modifyRecord(oldRe, newRe rewriteEntry) error {
|
||||||
|
rec := requestParams{
|
||||||
|
"target": oldRe,
|
||||||
|
"update": newRe,
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.write(http.MethodPut, "/control/rewrite/update", rec); err != nil {
|
||||||
|
return fmt.Errorf("failed to update record (adguard home): %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *adguardHomeProvider) getRecords(domain string) ([]rewriteEntry, error) {
|
||||||
|
bodyString, err := c.get("/control/rewrite/list")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch records from adguardhome: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var resp []rewriteEntry
|
||||||
|
err = json.Unmarshal(bodyString, &resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse records list from adguardhome: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
records := make([]rewriteEntry, 0, len(resp))
|
||||||
|
for _, r := range resp {
|
||||||
|
if !strings.HasSuffix(r.Domain, "."+domain) && r.Domain != domain {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
records = append(records, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
return records, nil
|
||||||
|
}
|
||||||
49
providers/adguardhome/auditrecords.go
Normal file
49
providers/adguardhome/auditrecords.go
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
package adguardhome
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/StackExchange/dnscontrol/v4/models"
|
||||||
|
"github.com/StackExchange/dnscontrol/v4/pkg/rejectif"
|
||||||
|
)
|
||||||
|
|
||||||
|
var supportedRTypes = map[string]struct{}{
|
||||||
|
"A": {},
|
||||||
|
"AAAA": {},
|
||||||
|
"CNAME": {},
|
||||||
|
"ALIAS": {},
|
||||||
|
"ADGUARDHOME_A_PASSTHROUGH": {},
|
||||||
|
"ADGUARDHOME_AAAA_PASSTHROUGH": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuditRecords returns a list of errors corresponding to the records
|
||||||
|
// that aren't supported by this provider. If all records are
|
||||||
|
// supported, an empty list is returned.
|
||||||
|
func AuditRecords(records []*models.RecordConfig) []error {
|
||||||
|
a := rejectif.Auditor{}
|
||||||
|
|
||||||
|
a.Add("ALIAS", rejectif.LabelNotApex)
|
||||||
|
|
||||||
|
a.Add("ADGUARDHOME_A_PASSTHROUGH", nonNullValue)
|
||||||
|
|
||||||
|
a.Add("ADGUARDHOME_AAAA_PASSTHROUGH", nonNullValue)
|
||||||
|
|
||||||
|
errors := []error{}
|
||||||
|
errors = append(errors, a.Audit(records)...)
|
||||||
|
|
||||||
|
for _, r := range records {
|
||||||
|
if _, ok := supportedRTypes[r.Type]; !ok {
|
||||||
|
errors = append(errors, fmt.Errorf("%s rtype is not supported", r.Type))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors
|
||||||
|
}
|
||||||
|
|
||||||
|
func nonNullValue(v *models.RecordConfig) error {
|
||||||
|
if len(v.GetTargetField()) != 0 {
|
||||||
|
return fmt.Errorf("%s rtype value should be empty", v.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue