FEAT: Add SMIMEA domain modifier

Add support for the RRtype SMIMEA used for discovering S/MIME certificates.
Also enabled this type for the providers bind and desec.
This commit is contained in:
Jan von Aschwege 2025-10-03 18:45:59 +02:00
parent 2be2b0fd1e
commit 04a70d2fc8
No known key found for this signature in database
GPG key ID: E43D3396A9061921
24 changed files with 384 additions and 148 deletions

View file

@ -115,6 +115,7 @@ func matrixData() *FeatureMatrix {
DomainModifierNaptr = "[`NAPTR`](../language-reference/domain-modifiers/NAPTR.md)"
DomainModifierOpenpgpkey = "[`DNSKEY`](../language-reference/domain-modifiers/OPENPGPKEY.md)"
DomainModifierPtr = "[`PTR`](../language-reference/domain-modifiers/PTR.md)"
DomainModifierSMIMEA = "[`SMIMEA`](../language-reference/domain-modifiers/SMIMEA.md)"
DomainModifierSoa = "[`SOA`](../language-reference/domain-modifiers/SOA.md)"
DomainModifierSrv = "[`SRV`](../language-reference/domain-modifiers/SRV.md)"
DomainModifierSshfp = "[`SSHFP`](../language-reference/domain-modifiers/SSHFP.md)"
@ -164,6 +165,7 @@ func matrixData() *FeatureMatrix {
[]string{ // security
DomainModifierCaa,
DomainModifierHTTPS,
DomainModifierSMIMEA,
DomainModifierSshfp,
DomainModifierTlsa,
},
@ -278,6 +280,10 @@ func matrixData() *FeatureMatrix {
DomainModifierPtr,
providers.CanUsePTR,
)
setCapability(
DomainModifierSMIMEA,
providers.CanUseSMIMEA,
)
setCapability(
DomainModifierSoa,
providers.CanUseSOA,

View file

@ -351,6 +351,8 @@ func formatDsl(rec *models.RecordConfig, defaultTTL uint32) string {
jsonQuoted(rec.NaptrRegexp), // regex
jsonQuoted(rec.GetTargetField()), // .
)
case "SMIMEA":
target = fmt.Sprintf(`%d, %d, %d, "%s"`, rec.SmimeaUsage, rec.SmimeaSelector, rec.SmimeaMatchingType, rec.GetTargetField())
case "SSHFP":
target = fmt.Sprintf(`%d, %d, "%s"`, rec.SshfpAlgorithm, rec.SshfpFingerprint, rec.GetTargetField())
case "SOA":

View file

@ -2870,6 +2870,38 @@ declare function REV(address: string): string;
*/
declare function REVCOMPAT(rfc: string): string;
/**
* `SMIMEA` adds a `SMIMEA` record to a domain. The name should be the hashed and stripped local part of the e-mail.
*
* To create the name, you can the following command:
*
* ```bash
* # For the e-mail bosun@bosun.org run:
* echo -n "bosun" | sha256sum | awk '{print $1}' | cut -c1-56
* # f10e7de079689f55c0cdd6782e4dd1448c84006962a4bd832e8eff73
* ```
*
* Usage, selector, and type are ints.
*
* Certificate is a hex string.
*
* To create the string for the type 0, you can run this command with your S/MIME certificate:
*
* ```bash
* openssl x509 -in smime-cert.pem -outform DER | xxd -p -c 10000
* ```
*
* ```javascript
* D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER),
* // Create SMIMEA record for certificate for the name bosun
* SMIMEA("f10e7de079689f55c0cdd6782e4dd1448c84006962a4bd832e8eff73", 3, 0, 0, "30820353308202f8a003020102..."),
* );
* ```
*
* @see https://docs.dnscontrol.org/language-reference/domain-modifiers/smimea
*/
declare function SMIMEA(name: string, usage: number, selector: number, type: number, certificate: string, ...modifiers: RecordModifier[]): DomainModifier;
/**
* `SOA` adds an `SOA` record to a domain. The name should be `@`. ns and mbox are strings. The other fields are unsigned 32-bit ints.
*

View file

@ -70,6 +70,7 @@
* [OPENPGPKEY](language-reference/domain-modifiers/OPENPGPKEY.md)
* [PTR](language-reference/domain-modifiers/PTR.md)
* [PURGE](language-reference/domain-modifiers/PURGE.md)
* [SMIMEA](language-reference/domain-modifiers/SMIMEA.md)
* [SOA](language-reference/domain-modifiers/SOA.md)
* [SPF_BUILDER](language-reference/domain-modifiers/SPF_BUILDER.md)
* [SRV](language-reference/domain-modifiers/SRV.md)

View file

@ -0,0 +1,46 @@
---
name: SMIMEA
parameters:
- name
- usage
- selector
- type
- certificate
- modifiers...
parameter_types:
name: string
usage: number
selector: number
type: number
certificate: string
"modifiers...": RecordModifier[]
---
`SMIMEA` adds a `SMIMEA` record to a domain. The name should be the hashed and stripped local part of the e-mail.
To create the name, you can the following command:
```bash
# For the e-mail bosun@bosun.org run:
echo -n "bosun" | sha256sum | awk '{print $1}' | cut -c1-56
# f10e7de079689f55c0cdd6782e4dd1448c84006962a4bd832e8eff73
```
Usage, selector, and type are ints.
Certificate is a hex string.
To create the string for the type 0, you can run this command with your S/MIME certificate:
```bash
openssl x509 -in smime-cert.pem -outform DER | xxd -p -c 10000
```
{% code title="dnsconfig.js" %}
```javascript
D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER),
// Create SMIMEA record for certificate for the name bosun
SMIMEA("f10e7de079689f55c0cdd6782e4dd1448c84006962a4bd832e8eff73", 3, 0, 0, "30820353308202f8a003020102..."),
);
```
{% endcode %}

View file

@ -252,53 +252,53 @@ Jump to a table:
### Security <!--(table 5/6)-->
| Provider name | [`CAA`](../language-reference/domain-modifiers/CAA.md) | [`HTTPS`](../language-reference/domain-modifiers/HTTPS.md) | [`SSHFP`](../language-reference/domain-modifiers/SSHFP.md) | [`TLSA`](../language-reference/domain-modifiers/TLSA.md) |
| ------------- | ------------------------------------------------------ | ---------------------------------------------------------- | ---------------------------------------------------------- | -------------------------------------------------------- |
| [`AKAMAIEDGEDNS`](akamaiedgedns.md) | ✅ | ❔ | ✅ | ✅ |
| [`AUTODNS`](autodns.md) | ✅ | ❔ | ❌ | ❌ |
| [`AXFRDDNS`](axfrddns.md) | ✅ | ✅ | ✅ | ✅ |
| [`AZURE_DNS`](azure_dns.md) | ✅ | ❔ | ❌ | ❌ |
| [`AZURE_PRIVATE_DNS`](azure_private_dns.md) | ❌ | ❔ | ❌ | ❌ |
| [`BIND`](bind.md) | ✅ | ✅ | ✅ | ✅ |
| [`BUNNY_DNS`](bunny_dns.md) | ✅ | ❔ | ❌ | ❌ |
| [`CLOUDFLAREAPI`](cloudflareapi.md) | ✅ | ✅ | ✅ | ✅ |
| [`CLOUDNS`](cloudns.md) | ✅ | ❌ | ✅ | ✅ |
| [`CNR`](cnr.md) | ✅ | ❌ | ✅ | ✅ |
| [`CSCGLOBAL`](cscglobal.md) | ✅ | ❔ | ❔ | ❔ |
| [`DESEC`](desec.md) | ✅ | ✅ | ✅ | ✅ |
| [`DIGITALOCEAN`](digitalocean.md) | ✅ | ❔ | ❔ | ❔ |
| [`DNSIMPLE`](dnsimple.md) | ✅ | ❔ | ✅ | ❌ |
| [`DNSMADEEASY`](dnsmadeeasy.md) | ✅ | ❔ | ❌ | ❌ |
| [`DOMAINNAMESHOP`](domainnameshop.md) | ✅ | ❔ | ❌ | ❔ |
| [`EXOSCALE`](exoscale.md) | ✅ | ❔ | ❔ | ❌ |
| [`GANDI_V5`](gandi_v5.md) | ✅ | ❔ | ✅ | ✅ |
| [`GCLOUD`](gcloud.md) | ✅ | ✅ | ✅ | ✅ |
| [`GCORE`](gcore.md) | ✅ | ✅ | ❌ | ❌ |
| [`HEDNS`](hedns.md) | ✅ | ✅ | ✅ | ❌ |
| [`HETZNER`](hetzner.md) | ✅ | ❔ | ❌ | ✅ |
| [`HEXONET`](hexonet.md) | ✅ | ❔ | ❔ | ✅ |
| [`HOSTINGDE`](hostingde.md) | ✅ | ❔ | ✅ | ✅ |
| [`HUAWEICLOUD`](huaweicloud.md) | ✅ | ❌ | ❌ | ❌ |
| [`INWX`](inwx.md) | ✅ | ✅ | ✅ | ✅ |
| [`JOKER`](joker.md) | ✅ | ❌ | ❌ | ❌ |
| [`LINODE`](linode.md) | ✅ | ❔ | ❔ | ❔ |
| [`LOOPIA`](loopia.md) | ✅ | ❌ | ✅ | ✅ |
| [`LUADNS`](luadns.md) | ✅ | ✅ | ✅ | ✅ |
| [`MYTHICBEASTS`](mythicbeasts.md) | ✅ | ❔ | ✅ | ✅ |
| [`NAMECHEAP`](namecheap.md) | ✅ | ❔ | ❔ | ❌ |
| [`NETCUP`](netcup.md) | ✅ | ❔ | ❔ | ❔ |
| [`NETLIFY`](netlify.md) | ✅ | ❔ | ❌ | ❌ |
| [`NS1`](ns1.md) | ✅ | ✅ | ❔ | ✅ |
| [`ORACLE`](oracle.md) | ✅ | ❔ | ✅ | ✅ |
| [`OVH`](ovh.md) | ✅ | ❔ | ✅ | ✅ |
| [`PORKBUN`](porkbun.md) | ✅ | ✅ | ❌ | ✅ |
| [`POWERDNS`](powerdns.md) | ✅ | ✅ | ✅ | ✅ |
| [`REALTIMEREGISTER`](realtimeregister.md) | ✅ | ❔ | ✅ | ✅ |
| [`ROUTE53`](route53.md) | ✅ | ✅ | ✅ | ✅ |
| [`RWTH`](rwth.md) | ✅ | ❔ | ✅ | ❌ |
| [`SAKURACLOUD`](sakuracloud.md) | ✅ | ✅ | ❌ | ❌ |
| [`TRANSIP`](transip.md) | ✅ | ❌ | ✅ | ✅ |
| [`VULTR`](vultr.md) | ✅ | ❔ | ✅ | ❌ |
| Provider name | [`CAA`](../language-reference/domain-modifiers/CAA.md) | [`HTTPS`](../language-reference/domain-modifiers/HTTPS.md) | [`SMIMEA`](../language-reference/domain-modifiers/SMIMEA.md) | [`SSHFP`](../language-reference/domain-modifiers/SSHFP.md) | [`TLSA`](../language-reference/domain-modifiers/TLSA.md) |
| ------------- | ------------------------------------------------------ | ---------------------------------------------------------- | ------------------------------------------------------------ | ---------------------------------------------------------- | -------------------------------------------------------- |
| [`AKAMAIEDGEDNS`](akamaiedgedns.md) | ✅ | ❔ | ❔ | ✅ | ✅ |
| [`AUTODNS`](autodns.md) | ✅ | ❔ | ❔ | ❌ | ❌ |
| [`AXFRDDNS`](axfrddns.md) | ✅ | ✅ | ❔ | ✅ | ✅ |
| [`AZURE_DNS`](azure_dns.md) | ✅ | ❔ | ❔ | ❌ | ❌ |
| [`AZURE_PRIVATE_DNS`](azure_private_dns.md) | ❌ | ❔ | ❔ | ❌ | ❌ |
| [`BIND`](bind.md) | ✅ | ✅ | ✅ | ✅ | ✅ |
| [`BUNNY_DNS`](bunny_dns.md) | ✅ | ❔ | ❔ | ❌ | ❌ |
| [`CLOUDFLAREAPI`](cloudflareapi.md) | ✅ | ✅ | ❔ | ✅ | ✅ |
| [`CLOUDNS`](cloudns.md) | ✅ | ❌ | ❔ | ✅ | ✅ |
| [`CNR`](cnr.md) | ✅ | ❌ | ❔ | ✅ | ✅ |
| [`CSCGLOBAL`](cscglobal.md) | ✅ | ❔ | ❔ | ❔ | ❔ |
| [`DESEC`](desec.md) | ✅ | ✅ | ✅ | ✅ | ✅ |
| [`DIGITALOCEAN`](digitalocean.md) | ✅ | ❔ | ❔ | ❔ | ❔ |
| [`DNSIMPLE`](dnsimple.md) | ✅ | ❔ | ❔ | ✅ | ❌ |
| [`DNSMADEEASY`](dnsmadeeasy.md) | ✅ | ❔ | ❔ | ❌ | ❌ |
| [`DOMAINNAMESHOP`](domainnameshop.md) | ✅ | ❔ | ❔ | ❌ | ❔ |
| [`EXOSCALE`](exoscale.md) | ✅ | ❔ | ❔ | ❔ | ❌ |
| [`GANDI_V5`](gandi_v5.md) | ✅ | ❔ | ❔ | ✅ | ✅ |
| [`GCLOUD`](gcloud.md) | ✅ | ✅ | ❔ | ✅ | ✅ |
| [`GCORE`](gcore.md) | ✅ | ✅ | ❔ | ❌ | ❌ |
| [`HEDNS`](hedns.md) | ✅ | ✅ | ❔ | ✅ | ❌ |
| [`HETZNER`](hetzner.md) | ✅ | ❔ | ❔ | ❌ | ✅ |
| [`HEXONET`](hexonet.md) | ✅ | ❔ | ❔ | ❔ | ✅ |
| [`HOSTINGDE`](hostingde.md) | ✅ | ❔ | ❔ | ✅ | ✅ |
| [`HUAWEICLOUD`](huaweicloud.md) | ✅ | ❌ | ❔ | ❌ | ❌ |
| [`INWX`](inwx.md) | ✅ | ✅ | ❔ | ✅ | ✅ |
| [`JOKER`](joker.md) | ✅ | ❌ | ❔ | ❌ | ❌ |
| [`LINODE`](linode.md) | ✅ | ❔ | ❔ | ❔ | ❔ |
| [`LOOPIA`](loopia.md) | ✅ | ❌ | ❔ | ✅ | ✅ |
| [`LUADNS`](luadns.md) | ✅ | ✅ | ❔ | ✅ | ✅ |
| [`MYTHICBEASTS`](mythicbeasts.md) | ✅ | ❔ | ❔ | ✅ | ✅ |
| [`NAMECHEAP`](namecheap.md) | ✅ | ❔ | ❔ | ❔ | ❌ |
| [`NETCUP`](netcup.md) | ✅ | ❔ | ❔ | ❔ | ❔ |
| [`NETLIFY`](netlify.md) | ✅ | ❔ | ❔ | ❌ | ❌ |
| [`NS1`](ns1.md) | ✅ | ✅ | ❔ | ❔ | ✅ |
| [`ORACLE`](oracle.md) | ✅ | ❔ | ❔ | ✅ | ✅ |
| [`OVH`](ovh.md) | ✅ | ❔ | ❔ | ✅ | ✅ |
| [`PORKBUN`](porkbun.md) | ✅ | ✅ | ❔ | ❌ | ✅ |
| [`POWERDNS`](powerdns.md) | ✅ | ✅ | ❔ | ✅ | ✅ |
| [`REALTIMEREGISTER`](realtimeregister.md) | ✅ | ❔ | ❔ | ✅ | ✅ |
| [`ROUTE53`](route53.md) | ✅ | ✅ | ❔ | ✅ | ✅ |
| [`RWTH`](rwth.md) | ✅ | ❔ | ❔ | ✅ | ❌ |
| [`SAKURACLOUD`](sakuracloud.md) | ✅ | ✅ | ❔ | ❌ | ❌ |
| [`TRANSIP`](transip.md) | ✅ | ❌ | ❔ | ✅ | ✅ |
| [`VULTR`](vultr.md) | ✅ | ❔ | ❔ | ✅ | ❌ |
### DNSSEC <!--(table 6/6)-->

View file

@ -479,6 +479,12 @@ func r53alias(name, aliasType, target, evalTargetHealth string) *models.RecordCo
return r
}
func smimea(name string, usage, selector, matchingtype uint8, target string) *models.RecordConfig {
r := makeRec(name, target, "SMIMEA")
panicOnErr(r.SetTargetSMIMEA(usage, selector, matchingtype, target))
return r
}
func soa(name string, ns, mbox string, serial, refresh, retry, expire, minttl uint32) *models.RecordConfig {
r := makeRec(name, "", "SOA")
panicOnErr(r.SetTargetSOA(ns, mbox, serial, refresh, retry, expire, minttl))

View file

@ -2021,6 +2021,15 @@ func makeTests() []*TestGroup {
tc("final", txt("final", `TestDNSProviders was successful!`)),
),
testgroup("SMIMEA",
requires(providers.CanUseSMIMEA),
tc("SMIMEA record", smimea("_443._tcp", 3, 1, 1, sha256hash)),
tc("SMIMEA change usage", smimea("_443._tcp", 2, 1, 1, sha256hash)),
tc("SMIMEA change selector", smimea("_443._tcp", 2, 0, 1, sha256hash)),
tc("SMIMEA change matchingtype", smimea("_443._tcp", 2, 0, 2, sha512hash)),
tc("SMIMEA change certificate", smimea("_443._tcp", 2, 0, 2, reversedSha512)),
),
// Narrative: Congrats! You're done! If you've made it this far
// you're very close to being able to submit your PR. Here's
// some tips:

View file

@ -68,6 +68,8 @@ func helperRRtoRC(rr dns.RR, origin string, fixBug bool) (RecordConfig, error) {
err = rc.SetTarget(v.Ns)
case *dns.PTR:
err = rc.SetTarget(v.Ptr)
case *dns.SMIMEA:
err = rc.SetTargetSMIMEA(v.Usage, v.Selector, v.MatchingType, v.Certificate)
case *dns.SOA:
err = rc.SetTargetSOA(v.Ns, v.Mbox, v.Serial, v.Refresh, v.Retry, v.Expire, v.Minttl)
case *dns.SRV:

View file

@ -142,7 +142,7 @@ func (dc *DomainConfig) Punycode() error {
if err := rec.SetTarget(rec.GetTargetField()); err != nil {
return err
}
case "A", "AAAA", "CAA", "DHCID", "DNSKEY", "DS", "HTTPS", "LOC", "NAPTR", "OPENPGPKEY", "SOA", "SSHFP", "SVCB", "TXT", "TLSA", "AZURE_ALIAS":
case "A", "AAAA", "CAA", "DHCID", "DNSKEY", "DS", "HTTPS", "LOC", "NAPTR", "OPENPGPKEY", "SMIMEA", "SOA", "SSHFP", "SVCB", "TXT", "TLSA", "AZURE_ALIAS":
// Nothing to do.
default:
return fmt.Errorf("Punycode rtype %v unimplemented", rec.Type)

View file

@ -28,6 +28,7 @@ import (
// NAPTR
// NS
// PTR
// SMIMEA
// SOA
// SRV
// SSHFP
@ -100,48 +101,51 @@ type RecordConfig struct {
Original interface{} `json:"-"` // Store pointer to provider-specific record object. Used in diffing.
// If you add a field to this struct, also add it to the list in the UnmarshalJSON function.
MxPreference uint16 `json:"mxpreference,omitempty"`
SrvPriority uint16 `json:"srvpriority,omitempty"`
SrvWeight uint16 `json:"srvweight,omitempty"`
SrvPort uint16 `json:"srvport,omitempty"`
CaaTag string `json:"caatag,omitempty"`
CaaFlag uint8 `json:"caaflag,omitempty"`
DsKeyTag uint16 `json:"dskeytag,omitempty"`
DsAlgorithm uint8 `json:"dsalgorithm,omitempty"`
DsDigestType uint8 `json:"dsdigesttype,omitempty"`
DsDigest string `json:"dsdigest,omitempty"`
DnskeyFlags uint16 `json:"dnskeyflags,omitempty"`
DnskeyProtocol uint8 `json:"dnskeyprotocol,omitempty"`
DnskeyAlgorithm uint8 `json:"dnskeyalgorithm,omitempty"`
DnskeyPublicKey string `json:"dnskeypublickey,omitempty"`
LocVersion uint8 `json:"locversion,omitempty"`
LocSize uint8 `json:"locsize,omitempty"`
LocHorizPre uint8 `json:"lochorizpre,omitempty"`
LocVertPre uint8 `json:"locvertpre,omitempty"`
LocLatitude uint32 `json:"loclatitude,omitempty"`
LocLongitude uint32 `json:"loclongitude,omitempty"`
LocAltitude uint32 `json:"localtitude,omitempty"`
NaptrOrder uint16 `json:"naptrorder,omitempty"`
NaptrPreference uint16 `json:"naptrpreference,omitempty"`
NaptrFlags string `json:"naptrflags,omitempty"`
NaptrService string `json:"naptrservice,omitempty"`
NaptrRegexp string `json:"naptrregexp,omitempty"`
SshfpAlgorithm uint8 `json:"sshfpalgorithm,omitempty"`
SshfpFingerprint uint8 `json:"sshfpfingerprint,omitempty"`
SoaMbox string `json:"soambox,omitempty"`
SoaSerial uint32 `json:"soaserial,omitempty"`
SoaRefresh uint32 `json:"soarefresh,omitempty"`
SoaRetry uint32 `json:"soaretry,omitempty"`
SoaExpire uint32 `json:"soaexpire,omitempty"`
SoaMinttl uint32 `json:"soaminttl,omitempty"`
SvcPriority uint16 `json:"svcpriority,omitempty"`
SvcParams string `json:"svcparams,omitempty"`
TlsaUsage uint8 `json:"tlsausage,omitempty"`
TlsaSelector uint8 `json:"tlsaselector,omitempty"`
TlsaMatchingType uint8 `json:"tlsamatchingtype,omitempty"`
R53Alias map[string]string `json:"r53_alias,omitempty"`
AzureAlias map[string]string `json:"azure_alias,omitempty"`
UnknownTypeName string `json:"unknown_type_name,omitempty"`
MxPreference uint16 `json:"mxpreference,omitempty"`
SrvPriority uint16 `json:"srvpriority,omitempty"`
SrvWeight uint16 `json:"srvweight,omitempty"`
SrvPort uint16 `json:"srvport,omitempty"`
CaaTag string `json:"caatag,omitempty"`
CaaFlag uint8 `json:"caaflag,omitempty"`
DsKeyTag uint16 `json:"dskeytag,omitempty"`
DsAlgorithm uint8 `json:"dsalgorithm,omitempty"`
DsDigestType uint8 `json:"dsdigesttype,omitempty"`
DsDigest string `json:"dsdigest,omitempty"`
DnskeyFlags uint16 `json:"dnskeyflags,omitempty"`
DnskeyProtocol uint8 `json:"dnskeyprotocol,omitempty"`
DnskeyAlgorithm uint8 `json:"dnskeyalgorithm,omitempty"`
DnskeyPublicKey string `json:"dnskeypublickey,omitempty"`
LocVersion uint8 `json:"locversion,omitempty"`
LocSize uint8 `json:"locsize,omitempty"`
LocHorizPre uint8 `json:"lochorizpre,omitempty"`
LocVertPre uint8 `json:"locvertpre,omitempty"`
LocLatitude uint32 `json:"loclatitude,omitempty"`
LocLongitude uint32 `json:"loclongitude,omitempty"`
LocAltitude uint32 `json:"localtitude,omitempty"`
NaptrOrder uint16 `json:"naptrorder,omitempty"`
NaptrPreference uint16 `json:"naptrpreference,omitempty"`
NaptrFlags string `json:"naptrflags,omitempty"`
NaptrService string `json:"naptrservice,omitempty"`
NaptrRegexp string `json:"naptrregexp,omitempty"`
SmimeaUsage uint8 `json:"smimeausage,omitempty"`
SmimeaSelector uint8 `json:"smimeaselector,omitempty"`
SmimeaMatchingType uint8 `json:"smimeamatchingtype,omitempty"`
SshfpAlgorithm uint8 `json:"sshfpalgorithm,omitempty"`
SshfpFingerprint uint8 `json:"sshfpfingerprint,omitempty"`
SoaMbox string `json:"soambox,omitempty"`
SoaSerial uint32 `json:"soaserial,omitempty"`
SoaRefresh uint32 `json:"soarefresh,omitempty"`
SoaRetry uint32 `json:"soaretry,omitempty"`
SoaExpire uint32 `json:"soaexpire,omitempty"`
SoaMinttl uint32 `json:"soaminttl,omitempty"`
SvcPriority uint16 `json:"svcpriority,omitempty"`
SvcParams string `json:"svcparams,omitempty"`
TlsaUsage uint8 `json:"tlsausage,omitempty"`
TlsaSelector uint8 `json:"tlsaselector,omitempty"`
TlsaMatchingType uint8 `json:"tlsamatchingtype,omitempty"`
R53Alias map[string]string `json:"r53_alias,omitempty"`
AzureAlias map[string]string `json:"azure_alias,omitempty"`
UnknownTypeName string `json:"unknown_type_name,omitempty"`
// Cloudflare-specific fields:
// When these are used, .target is set to a human-readable version (only to be used for display purposes).
@ -200,48 +204,51 @@ func (rc *RecordConfig) UnmarshalJSON(b []byte) error {
Original interface{} `json:"-"` // Store pointer to provider-specific record object. Used in diffing.
Args []any `json:"args,omitempty"`
MxPreference uint16 `json:"mxpreference,omitempty"`
SrvPriority uint16 `json:"srvpriority,omitempty"`
SrvWeight uint16 `json:"srvweight,omitempty"`
SrvPort uint16 `json:"srvport,omitempty"`
CaaTag string `json:"caatag,omitempty"`
CaaFlag uint8 `json:"caaflag,omitempty"`
DsKeyTag uint16 `json:"dskeytag,omitempty"`
DsAlgorithm uint8 `json:"dsalgorithm,omitempty"`
DsDigestType uint8 `json:"dsdigesttype,omitempty"`
DsDigest string `json:"dsdigest,omitempty"`
DnskeyFlags uint16 `json:"dnskeyflags,omitempty"`
DnskeyProtocol uint8 `json:"dnskeyprotocol,omitempty"`
DnskeyAlgorithm uint8 `json:"dnskeyalgorithm,omitempty"`
DnskeyPublicKey string `json:"dnskeypublickey,omitempty"`
LocVersion uint8 `json:"locversion,omitempty"`
LocSize uint8 `json:"locsize,omitempty"`
LocHorizPre uint8 `json:"lochorizpre,omitempty"`
LocVertPre uint8 `json:"locvertpre,omitempty"`
LocLatitude int `json:"loclatitude,omitempty"`
LocLongitude int `json:"loclongitude,omitempty"`
LocAltitude uint32 `json:"localtitude,omitempty"`
NaptrOrder uint16 `json:"naptrorder,omitempty"`
NaptrPreference uint16 `json:"naptrpreference,omitempty"`
NaptrFlags string `json:"naptrflags,omitempty"`
NaptrService string `json:"naptrservice,omitempty"`
NaptrRegexp string `json:"naptrregexp,omitempty"`
SshfpAlgorithm uint8 `json:"sshfpalgorithm,omitempty"`
SshfpFingerprint uint8 `json:"sshfpfingerprint,omitempty"`
SoaMbox string `json:"soambox,omitempty"`
SoaSerial uint32 `json:"soaserial,omitempty"`
SoaRefresh uint32 `json:"soarefresh,omitempty"`
SoaRetry uint32 `json:"soaretry,omitempty"`
SoaExpire uint32 `json:"soaexpire,omitempty"`
SoaMinttl uint32 `json:"soaminttl,omitempty"`
SvcPriority uint16 `json:"svcpriority,omitempty"`
SvcParams string `json:"svcparams,omitempty"`
TlsaUsage uint8 `json:"tlsausage,omitempty"`
TlsaSelector uint8 `json:"tlsaselector,omitempty"`
TlsaMatchingType uint8 `json:"tlsamatchingtype,omitempty"`
R53Alias map[string]string `json:"r53_alias,omitempty"`
AzureAlias map[string]string `json:"azure_alias,omitempty"`
UnknownTypeName string `json:"unknown_type_name,omitempty"`
MxPreference uint16 `json:"mxpreference,omitempty"`
SrvPriority uint16 `json:"srvpriority,omitempty"`
SrvWeight uint16 `json:"srvweight,omitempty"`
SrvPort uint16 `json:"srvport,omitempty"`
CaaTag string `json:"caatag,omitempty"`
CaaFlag uint8 `json:"caaflag,omitempty"`
DsKeyTag uint16 `json:"dskeytag,omitempty"`
DsAlgorithm uint8 `json:"dsalgorithm,omitempty"`
DsDigestType uint8 `json:"dsdigesttype,omitempty"`
DsDigest string `json:"dsdigest,omitempty"`
DnskeyFlags uint16 `json:"dnskeyflags,omitempty"`
DnskeyProtocol uint8 `json:"dnskeyprotocol,omitempty"`
DnskeyAlgorithm uint8 `json:"dnskeyalgorithm,omitempty"`
DnskeyPublicKey string `json:"dnskeypublickey,omitempty"`
LocVersion uint8 `json:"locversion,omitempty"`
LocSize uint8 `json:"locsize,omitempty"`
LocHorizPre uint8 `json:"lochorizpre,omitempty"`
LocVertPre uint8 `json:"locvertpre,omitempty"`
LocLatitude int `json:"loclatitude,omitempty"`
LocLongitude int `json:"loclongitude,omitempty"`
LocAltitude uint32 `json:"localtitude,omitempty"`
NaptrOrder uint16 `json:"naptrorder,omitempty"`
NaptrPreference uint16 `json:"naptrpreference,omitempty"`
NaptrFlags string `json:"naptrflags,omitempty"`
NaptrService string `json:"naptrservice,omitempty"`
NaptrRegexp string `json:"naptrregexp,omitempty"`
SmimeaUsage uint8 `json:"smimeausage,omitempty"`
SmimeaSelector uint8 `json:"smimeaselector,omitempty"`
SmimeaMatchingType uint8 `json:"smimeamatchingtype,omitempty"`
SshfpAlgorithm uint8 `json:"sshfpalgorithm,omitempty"`
SshfpFingerprint uint8 `json:"sshfpfingerprint,omitempty"`
SoaMbox string `json:"soambox,omitempty"`
SoaSerial uint32 `json:"soaserial,omitempty"`
SoaRefresh uint32 `json:"soarefresh,omitempty"`
SoaRetry uint32 `json:"soaretry,omitempty"`
SoaExpire uint32 `json:"soaexpire,omitempty"`
SoaMinttl uint32 `json:"soaminttl,omitempty"`
SvcPriority uint16 `json:"svcpriority,omitempty"`
SvcParams string `json:"svcparams,omitempty"`
TlsaUsage uint8 `json:"tlsausage,omitempty"`
TlsaSelector uint8 `json:"tlsaselector,omitempty"`
TlsaMatchingType uint8 `json:"tlsamatchingtype,omitempty"`
R53Alias map[string]string `json:"r53_alias,omitempty"`
AzureAlias map[string]string `json:"azure_alias,omitempty"`
UnknownTypeName string `json:"unknown_type_name,omitempty"`
EnsureAbsent bool `json:"ensure_absent,omitempty"` // Override NO_PURGE and delete this record
@ -448,6 +455,11 @@ func (rc *RecordConfig) ToRR() dns.RR {
rr.(*dns.OPENPGPKEY).PublicKey = rc.GetTargetField()
case dns.TypePTR:
rr.(*dns.PTR).Ptr = rc.GetTargetField()
case dns.TypeSMIMEA:
rr.(*dns.SMIMEA).Usage = rc.SmimeaUsage
rr.(*dns.SMIMEA).MatchingType = rc.SmimeaMatchingType
rr.(*dns.SMIMEA).Selector = rc.SmimeaSelector
rr.(*dns.SMIMEA).Certificate = rc.GetTargetField()
case dns.TypeSOA:
rr.(*dns.SOA).Ns = rc.GetTargetField()
rr.(*dns.SOA).Mbox = rc.SoaMbox
@ -617,7 +629,7 @@ func Downcase(recs []*RecordConfig) {
r.Name = strings.ToLower(r.Name)
r.NameFQDN = strings.ToLower(r.NameFQDN)
switch r.Type { // #rtype_variations
case "AKAMAICDN", "ALIAS", "AAAA", "ANAME", "CNAME", "DNAME", "DS", "DNSKEY", "MX", "NS", "NAPTR", "OPENPGPKEY", "PTR", "SRV", "TLSA", "AZURE_ALIAS":
case "AKAMAICDN", "ALIAS", "AAAA", "ANAME", "CNAME", "DNAME", "DS", "DNSKEY", "MX", "NS", "NAPTR", "OPENPGPKEY", "SMIMEA", "PTR", "SRV", "TLSA", "AZURE_ALIAS":
// Target is case insensitive. Downcase it.
r.target = strings.ToLower(r.target)
// BUGFIX(tlim): isn't ALIAS in the wrong case statement?
@ -645,7 +657,7 @@ func CanonicalizeTargets(recs []*RecordConfig, origin string) {
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.
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", "OPENPGPKEY", "SSHFP", "SVCB", "TLSA", "TXT", "ADGUARDHOME_A_PASSTHROUGH", "ADGUARDHOME_AAAA_PASSTHROUGH":
case "A", "AKAMAICDN", "CAA", "DHCID", "CLOUDFLAREAPI_SINGLE_REDIRECT", "CF_REDIRECT", "CF_TEMP_REDIRECT", "CF_WORKER_ROUTE", "HTTPS", "IMPORT_TRANSFORM", "LOC", "OPENPGPKEY", "SMIMEA", "SSHFP", "SVCB", "TLSA", "TXT", "ADGUARDHOME_A_PASSTHROUGH", "ADGUARDHOME_AAAA_PASSTHROUGH":
// Do nothing.
case "SOA":
if r.target != "DEFAULT_NOT_SET." {

View file

@ -92,6 +92,8 @@ func (rc *RecordConfig) PopulateFromStringFunc(rtype, contents, origin string, t
return rc.SetTargetNAPTRString(contents)
case "OPENPGPKEY":
return rc.SetTarget(contents)
case "SMIMEA":
return rc.SetTargetSMIMEAString(contents)
case "SOA":
return rc.SetTargetSOAString(contents)
case "SPF", "TXT":
@ -184,6 +186,8 @@ func (rc *RecordConfig) PopulateFromString(rtype, contents, origin string) error
return rc.SetTargetNAPTRString(contents)
case "OPENPGPKEY":
return rc.SetTarget(contents)
case "SMIMEA":
return rc.SetTargetSMIMEAString(contents)
case "SOA":
return rc.SetTargetSOAString(contents)
case "SPF", "TXT":

46
models/t_smimea.go Normal file
View file

@ -0,0 +1,46 @@
package models
import (
"fmt"
"strconv"
"strings"
)
// SetTargetSMIMEA sets the SMIMEA fields.
func (rc *RecordConfig) SetTargetSMIMEA(usage, selector, matchingtype uint8, target string) error {
rc.SmimeaUsage = usage
rc.SmimeaSelector = selector
rc.SmimeaMatchingType = matchingtype
if err := rc.SetTarget(target); err != nil {
return err
}
if rc.Type == "" {
rc.Type = "SMIMEA"
}
if rc.Type != "SMIMEA" {
panic("assertion failed: SetTargetSMIMEA called when .Type is not SMIMEA")
}
return nil
}
// SetTargetSMIMEAStrings is like SetTargetSMIMEA but accepts strings.
func (rc *RecordConfig) SetTargetSMIMEAStrings(usage, selector, matchingtype, target string) (err error) {
var i64usage, i64selector, i64matchingtype uint64
if i64usage, err = strconv.ParseUint(usage, 10, 8); err == nil {
if i64selector, err = strconv.ParseUint(selector, 10, 8); err == nil {
if i64matchingtype, err = strconv.ParseUint(matchingtype, 10, 8); err == nil {
return rc.SetTargetSMIMEA(uint8(i64usage), uint8(i64selector), uint8(i64matchingtype), target)
}
}
}
return fmt.Errorf("SMIMEA has value that won't fit in field: %w", err)
}
// SetTargetSMIMEAString is like SetTargetSMIMEA but accepts one big string.
func (rc *RecordConfig) SetTargetSMIMEAString(s string) error {
part := strings.Fields(s)
if len(part) != 4 {
return fmt.Errorf("SMIMEA value does not contain 4 fields: (%#v)", s)
}
return rc.SetTargetSMIMEAStrings(part[0], part[1], part[2], part[3])
}

View file

@ -124,6 +124,8 @@ func (rc *RecordConfig) GetTargetDebug() string {
content += fmt.Sprintf(" naptrorder=%d naptrpreference=%d naptrflags=%s naptrservice=%s naptrregexp=%s", rc.NaptrOrder, rc.NaptrPreference, rc.NaptrFlags, rc.NaptrService, rc.NaptrRegexp)
case "R53_ALIAS":
content += fmt.Sprintf(" type=%s zone_id=%s evaluate_target_health=%s", rc.R53Alias["type"], rc.R53Alias["zone_id"], rc.R53Alias["evaluate_target_health"])
case "SMIMEA":
content += fmt.Sprintf(" smimeausage=%d smimeaselector=%d smimeamatchingtype=%d", rc.SmimeaUsage, rc.SmimeaSelector, rc.SmimeaMatchingType)
case "SOA":
content = fmt.Sprintf("%s ns=%v mbox=%v serial=%v refresh=%v retry=%v expire=%v minttl=%v", rc.Type, rc.target, rc.SoaMbox, rc.SoaSerial, rc.SoaRefresh, rc.SoaRetry, rc.SoaExpire, rc.SoaMinttl)
case "SRV":

View file

@ -1,6 +1,6 @@
{
"dependencies": {
"@umbrelladocs/linkspector": "^0.3.13",
"prettier": "^3.5.3"
"prettier": "^3.6.2"
}
}

View file

@ -536,6 +536,24 @@ var NAPTR = recordBuilder('NAPTR', {
// OPENPGPKEY(name,target, recordModifiers...)
var OPENPGPKEY = recordBuilder('OPENPGPKEY');
// name, usage, selector, matchingtype, certificate
var SMIMEA = recordBuilder('SMIMEA', {
args: [
['name', _.isString],
['usage', _.isNumber],
['selector', _.isNumber],
['matchingtype', _.isNumber],
['target', _.isString], // recordBuilder needs a "target" argument
],
transform: function (record, args, modifiers) {
record.name = args.name + '._smimecert';
record.smimeausage = args.usage;
record.smimeaselector = args.selector;
record.smimeamatchingtype = args.matchingtype;
record.target = args.target;
},
});
// SOA(name,ns,mbox,refresh,retry,expire,minimum, recordModifiers...)
var SOA = recordBuilder('SOA', {
args: [

View file

@ -0,0 +1,3 @@
D("foo.com", "none",
SMIMEA("f10e7de079689f55c0cdd6782e4dd1448c84006962a4bd832e8eff73", 3, 0, 0, "MDFiYTQ3MTljODBiNmZlOTExYjA5MWE3YzA1MTI0YjY0ZWVlY2U5NjRlMDljMDU4ZWY4Zjk4MDVkYWNhNTQ2YiAgLQo="),
);

View file

@ -0,0 +1,24 @@
{
"dns_providers": [],
"domains": [
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": "",
"dnscontrol_uniquename": "foo.com"
},
"name": "foo.com",
"records": [
{
"name": "f10e7de079689f55c0cdd6782e4dd1448c84006962a4bd832e8eff73._smimecert",
"smimeausage": 3,
"target": "mdfiytq3mtljodbinmzlotexyja5mwe3yza1mti0yjy0zwvly2u5njrlmdljmdu4zwy4zjk4mdvkywnhntq2yiaglqo=",
"ttl": 300,
"type": "SMIMEA"
}
],
"registrar": "none"
}
],
"registrars": []
}

View file

@ -73,6 +73,7 @@ func validateRecordTypes(rec *models.RecordConfig, domain string, pTypes []strin
"NS": true,
"OPENPGPKEY": true,
"PTR": true,
"SMIMEA": true,
"SOA": true,
"SRV": true,
"SSHFP": true,
@ -225,7 +226,7 @@ func checkTargets(rec *models.RecordConfig, domain string) (errs []error) {
}
case "SRV":
check(checkTarget(target))
case "CAA", "DHCID", "DNSKEY", "DS", "HTTPS", "IMPORT_TRANSFORM", "OPENPGPKEY", "SSHFP", "SVCB", "TLSA", "TXT":
case "CAA", "DHCID", "DNSKEY", "DS", "HTTPS", "IMPORT_TRANSFORM", "OPENPGPKEY", "SMIMEA", "SSHFP", "SVCB", "TLSA", "TXT":
default:
if rec.Metadata["orig_custom_type"] != "" {
// it is a valid custom type. We perform no validation on target
@ -461,6 +462,19 @@ func ValidateAndNormalizeConfig(config *models.DNSConfig) (errs []error) {
errs = append(errs, fmt.Errorf("TLSA MatchingType %d is invalid in record %s (domain %s)",
rec.TlsaMatchingType, rec.GetLabel(), domain.Name))
}
} else if rec.Type == "SMIMEA" {
if rec.SmimeaUsage > 3 {
errs = append(errs, fmt.Errorf("SMIMEA Usage %d is invalid in record %s (domain %s)",
rec.SmimeaUsage, rec.GetLabel(), domain.Name))
}
if rec.SmimeaSelector > 1 {
errs = append(errs, fmt.Errorf("SMIMEA Selector %d is invalid in record %s (domain %s)",
rec.SmimeaSelector, rec.GetLabel(), domain.Name))
}
if rec.SmimeaMatchingType > 2 {
errs = append(errs, fmt.Errorf("SMIMEA MatchingType %d is invalid in record %s (domain %s)",
rec.SmimeaMatchingType, rec.GetLabel(), domain.Name))
}
}
// Populate FQDN:
@ -731,6 +745,7 @@ var providerCapabilityChecks = []pairTypeCapability{
capabilityCheck("OPENPGPKEY", providers.CanUseOPENPGPKEY),
capabilityCheck("PTR", providers.CanUsePTR),
capabilityCheck("R53_ALIAS", providers.CanUseRoute53Alias),
capabilityCheck("SMIMEA", providers.CanUseSMIMEA),
capabilityCheck("SOA", providers.CanUseSOA),
capabilityCheck("SRV", providers.CanUseSRV),
capabilityCheck("SSHFP", providers.CanUseSSHFP),

View file

@ -359,6 +359,7 @@ func TestWriteZoneFileEach(t *testing.T) {
d = append(d, mustNewRR(`bosun.org. 300 IN HTTPS 1 . alpn="h3,h2"`))
d = append(d, mustNewRR(`bosun.org. 300 IN SVCB 1 . alpn="h3,h2"`))
d = append(d, mustNewRR(`9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15._openpgpkey.bosun.org. 300 IN OPENPGPKEY 9901a204447450b7110400d9bef554b145128ccc90d9f52df14bb878626e3db32112d47fbc5ee9cc5ffcbbd06bee487a580481674d9d31e368a85ccf4d4ef3bfa3e23fdde238bc32d8c40d39204b912f8cb1c47a7f34ba64bf3598dafe0f080e17facb678b6e700b0163d677960471d265a197e5ee9d53d71e1911f47f518a0e303abaf3c01b188e37d7bf00a0b90d4f43af944202fc49356a35a367955633cd4503ff7dfa21fb70a201ffb4aa7a755fc560ffd5a4b1d7b7015e7b4bdc0a1e45c1c28fd2f628f4d21f07a091da0d29c98b070566e178c5974554e509a5153a16b271df835e8c8a97715cc4beb5383d05fdf7a0d9412a1fb9f572c195d8c0c696a5ec179bab29d3d8701446e7aca79565ecdd6ec3ceef4937cb248564a75ddb4115adc10400a8f820174b32c99c5ac6ee483c0184fed24fa44d2fd4c9dc00af9ed048b51cfdb95747ab1e35df933382b08f8223da934bfcba59cb356b0d2f4158d647ab76d09c444fadf5e92b95d65f4aae667f33835226170c6625db872a6b72cb13638cf4754941730f5117a4f7c262044bea453839f95b806a0bd98a668073ba2d0fce1ab4326f70656e53555345204275696c642053657276696365203c6275696c6473657276696365406f70656e737573652e6f72673e8864041311020024021b03060b09080703020315020303160201021e01021780050253674e3b050921bf0084000a09103b3011b76b9d65234a5b00a095c38bcfaa29f80adefc0cf9ba2abf3a3e9b516b009e367296e1a96af211f8cded2493f7f6ac09de41`))
d = append(d, mustNewRR(`f10e7de079689f55c0cdd6782e4dd1448c84006962a4bd832e8eff73._smimecert.bosun.org. 300 IN SMIMEA 3 0 0 abcdef0`)) // Label must be the local part of mail address hashed with SHA2-256 and truncated to 28 octets, followed by _smimecert
buf := &bytes.Buffer{}
if err := writeZoneFileRR(buf, d, "bosun.org"); err != nil {
t.Fatal(err)
@ -383,6 +384,7 @@ var testdataZFEach = `$TTL 300
IN SVCB 1 . alpn="h3,h2"
4.5 IN PTR y.bosun.org.
9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15._openpgpkey IN OPENPGPKEY 9901a204447450b7110400d9bef554b145128ccc90d9f52df14bb878626e3db32112d47fbc5ee9cc5ffcbbd06bee487a580481674d9d31e368a85ccf4d4ef3bfa3e23fdde238bc32d8c40d39204b912f8cb1c47a7f34ba64bf3598dafe0f080e17facb678b6e700b0163d677960471d265a197e5ee9d53d71e1911f47f518a0e303abaf3c01b188e37d7bf00a0b90d4f43af944202fc49356a35a367955633cd4503ff7dfa21fb70a201ffb4aa7a755fc560ffd5a4b1d7b7015e7b4bdc0a1e45c1c28fd2f628f4d21f07a091da0d29c98b070566e178c5974554e509a5153a16b271df835e8c8a97715cc4beb5383d05fdf7a0d9412a1fb9f572c195d8c0c696a5ec179bab29d3d8701446e7aca79565ecdd6ec3ceef4937cb248564a75ddb4115adc10400a8f820174b32c99c5ac6ee483c0184fed24fa44d2fd4c9dc00af9ed048b51cfdb95747ab1e35df933382b08f8223da934bfcba59cb356b0d2f4158d647ab76d09c444fadf5e92b95d65f4aae667f33835226170c6625db872a6b72cb13638cf4754941730f5117a4f7c262044bea453839f95b806a0bd98a668073ba2d0fce1ab4326f70656e53555345204275696c642053657276696365203c6275696c6473657276696365406f70656e737573652e6f72673e8864041311020024021b03060b09080703020315020303160201021e01021780050253674e3b050921bf0084000a09103b3011b76b9d65234a5b00a095c38bcfaa29f80adefc0cf9ba2abf3a3e9b516b009e367296e1a96af211f8cded2493f7f6ac09de41
f10e7de079689f55c0cdd6782e4dd1448c84006962a4bd832e8eff73._smimecert IN SMIMEA 3 0 0 abcdef0
_443._tcp IN TLSA 3 1 1 abcdef0
dname IN DNAME example.com.
dnssec IN DNSKEY 257 3 13 rNR701yiOPHfqDP53GnsHZdlsRqI7O1ksk60rnFILZVk7Z4eTBd1U49oSkTNVNox9tb7N15N2hboXoMEyFFzcw==

View file

@ -46,6 +46,7 @@ var features = providers.DocumentationNotes{
providers.CanUseNAPTR: providers.Can(),
providers.CanUseOPENPGPKEY: providers.Can(),
providers.CanUsePTR: providers.Can(),
providers.CanUseSMIMEA: providers.Can(),
providers.CanUseSOA: providers.Can(),
providers.CanUseSRV: providers.Can(),
providers.CanUseSSHFP: providers.Can(),

View file

@ -79,6 +79,9 @@ const (
// CanUseRoute53Alias indicates the provider support the specific R53_ALIAS records that only the Route53 provider supports
CanUseRoute53Alias
// CanUseSMIMEA indicates the provider can handle SMIMEA records
CanUseSMIMEA
// CanUseSOA indicates the provider supports full management of a zone's SOA record
CanUseSOA

View file

@ -25,21 +25,22 @@ func _() {
_ = x[CanUseNAPTR-14]
_ = x[CanUsePTR-15]
_ = x[CanUseRoute53Alias-16]
_ = x[CanUseSOA-17]
_ = x[CanUseSRV-18]
_ = x[CanUseSSHFP-19]
_ = x[CanUseSVCB-20]
_ = x[CanUseTLSA-21]
_ = x[CanUseDNSKEY-22]
_ = x[CanUseOPENPGPKEY-23]
_ = x[DocCreateDomains-24]
_ = x[DocDualHost-25]
_ = x[DocOfficiallySupported-26]
_ = x[CanUseSMIMEA-17]
_ = x[CanUseSOA-18]
_ = x[CanUseSRV-19]
_ = x[CanUseSSHFP-20]
_ = x[CanUseSVCB-21]
_ = x[CanUseTLSA-22]
_ = x[CanUseDNSKEY-23]
_ = x[CanUseOPENPGPKEY-24]
_ = x[DocCreateDomains-25]
_ = x[DocDualHost-26]
_ = x[DocOfficiallySupported-27]
}
const _Capability_name = "CanAutoDNSSECCanConcurCanGetZonesCanOnlyDiff1FeaturesCanUseAKAMAICDNCanUseAliasCanUseAzureAliasCanUseCAACanUseDHCIDCanUseDNAMECanUseDSCanUseDSForChildrenCanUseHTTPSCanUseLOCCanUseNAPTRCanUsePTRCanUseRoute53AliasCanUseSOACanUseSRVCanUseSSHFPCanUseSVCBCanUseTLSACanUseDNSKEYCanUseOPENPGPKEYDocCreateDomainsDocDualHostDocOfficiallySupported"
const _Capability_name = "CanAutoDNSSECCanConcurCanGetZonesCanOnlyDiff1FeaturesCanUseAKAMAICDNCanUseAliasCanUseAzureAliasCanUseCAACanUseDHCIDCanUseDNAMECanUseDSCanUseDSForChildrenCanUseHTTPSCanUseLOCCanUseNAPTRCanUsePTRCanUseRoute53AliasCanUseSMIMEACanUseSOACanUseSRVCanUseSSHFPCanUseSVCBCanUseTLSACanUseDNSKEYCanUseOPENPGPKEYDocCreateDomainsDocDualHostDocOfficiallySupported"
var _Capability_index = [...]uint16{0, 13, 22, 33, 53, 68, 79, 95, 104, 115, 126, 134, 153, 164, 173, 184, 193, 211, 220, 229, 240, 250, 260, 272, 288, 304, 315, 337}
var _Capability_index = [...]uint16{0, 13, 22, 33, 53, 68, 79, 95, 104, 115, 126, 134, 153, 164, 173, 184, 193, 211, 223, 232, 241, 252, 262, 272, 284, 300, 316, 327, 349}
func (i Capability) String() string {
if i >= Capability(len(_Capability_index)-1) {

View file

@ -46,6 +46,7 @@ var features = providers.DocumentationNotes{
providers.CanUseLOC: providers.Unimplemented(),
providers.CanUseNAPTR: providers.Can(),
providers.CanUsePTR: providers.Can(),
providers.CanUseSMIMEA: providers.Can(),
providers.CanUseSRV: providers.Can(),
providers.CanUseSSHFP: providers.Can(),
providers.CanUseSVCB: providers.Can(),