FEATURE: Support ignoring the ech= parameter in HTTPS/SVCB RR types (#3485)

This commit is contained in:
Max Chernoff 2025-06-11 09:16:15 -06:00 committed by GitHub
parent 1a7cb20599
commit 3ea7ea84c9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 47 additions and 0 deletions

View file

@ -1181,6 +1181,8 @@ declare function HASH(algorithm: "SHA1" | "SHA256" | "SHA512", value: string): s
*
* Modifiers can be any number of [record modifiers](https://docs.dnscontrol.org/language-reference/record-modifiers) or JSON objects, which will be merged into the record's metadata.
*
* If you set the parameter `ech` to the special value `IGNORE`, DNSControl will ignore the contents of that parameter when updating a zone.
*
* ```javascript
* D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER),
* HTTPS("@", 1, ".", "ipv4hint=123.123.123.123 alpn=h3,h2 port=443"),

View file

@ -22,6 +22,8 @@ The params may be configured to specify the `alpn`, `ipv4hint`, `ipv6hint`, `ech
Modifiers can be any number of [record modifiers](https://docs.dnscontrol.org/language-reference/record-modifiers) or JSON objects, which will be merged into the record's metadata.
If you set the parameter `ech` to the special value `IGNORE`, DNSControl will ignore the contents of that parameter when updating a zone.
{% code title="dnsconfig.js" %}
```javascript
D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER),

View file

@ -288,6 +288,18 @@ func makeTests() []*TestGroup {
tc("Change HTTPS all", https("@", 3, "example.com.", "port=100")),
),
testgroup("Ech",
requires(providers.CanUseHTTPS),
tc("Create a HTTPS record", https("@", 1, "example.com.", "alpn=h2,h3")),
tc("Add an ECH key", https("@", 1, "example.com.", "alpn=h2,h3 ech=some+base64+encoded+value///")),
tc("Ignore the ECH key while changing other values", https("@", 1, "example.net.", "port=80 ech=IGNORE")),
// tc("Should be a no-op", https("@", 1, "example.net.", "port=80 ech=some+base64+encoded+value///")),
tc("Change the ECH key and other values", https("@", 1, "example.org.", "port=80 ipv4hint=127.0.0.1 ech=another+base64+encoded+value")),
// tc("Ignore the ECH key while not changing anything", https("@", 1, "example.org.", "port=80 ipv4hint=127.0.0.1 ech=IGNORE")),
// tc("Should be a no-op", https("@", 1, "example.org.", "port=80 ipv4hint=127.0.0.1 ech=another+base64+encoded+value")),
tc("Another domain with a different ECH value", https("ech", 1, "example.com.", "ech=some+base64+encoded+value///")),
),
testgroup("SVCB",
requires(providers.CanUseSVCB),
tc("Create a SVCB record", svcb("@", 1, "test.com.", "port=80")),

View file

@ -529,6 +529,10 @@ func (rc *RecordConfig) Key() RecordKey {
// GetSVCBValue returns the SVCB Key/Values as a list of Key/Values.
func (rc *RecordConfig) GetSVCBValue() []dns.SVCBKeyValue {
if !strings.Contains(rc.SvcParams, "IGNORE+DNSCONTROL") {
rc.SvcParams = strings.ReplaceAll(rc.SvcParams, "ech=IGNORE", "ech=IGNORE+DNSCONTROL+++")
}
record, err := dns.NewRR(fmt.Sprintf("%s %s %d %s %s", rc.NameFQDN, rc.Type, rc.SvcPriority, rc.target, rc.SvcParams))
if err != nil {
log.Fatalf("could not parse SVCB record: %s", err)

View file

@ -2,6 +2,7 @@ package diff2
import (
"fmt"
"regexp"
"sort"
"strings"
@ -247,6 +248,8 @@ func humanDiff(a, b targetConfig) string {
return fmt.Sprintf("%s ttl=(%d->%d)", a.comparableNoTTL, a.rec.TTL, b.rec.TTL)
}
var echRe = regexp.MustCompile(`ech="?([\w+/=]+)"?`)
func diffTargets(existing, desired []targetConfig) ChangeList {
// fmt.Printf("DEBUG: diffTargets(\nexisting=%v\ndesired=%v\nDEBUG.\n", existing, desired)
@ -255,6 +258,30 @@ func diffTargets(existing, desired []targetConfig) ChangeList {
return nil
}
echs := make(map[string]string)
for _, v := range existing {
matches := echRe.FindStringSubmatch(v.rec.SvcParams)
if len(matches) == 2 {
echs[v.rec.NameFQDN] = matches[1]
}
}
for i, v := range desired {
if strings.Contains(v.rec.SvcParams, "ech=IGNORE") {
var unquoted, quoted string
if _, ok := echs[v.rec.NameFQDN]; ok {
unquoted = fmt.Sprintf("ech=%s", echs[v.rec.NameFQDN])
quoted = fmt.Sprintf("ech=%q", echs[v.rec.NameFQDN])
} else {
unquoted = ""
quoted = ""
}
v.rec.SvcParams = echRe.ReplaceAllString(v.rec.SvcParams, unquoted)
v.comparableFull = echRe.ReplaceAllString(v.comparableFull, quoted)
v.comparableNoTTL = echRe.ReplaceAllString(v.comparableNoTTL, quoted)
}
desired[i] = v
}
var instructions ChangeList
// remove the exact matches.