mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2025-12-09 13:46:07 +08:00
VERCEL: Fix some bugs (#3887)
The PR follows https://github.com/StackExchange/dnscontrol/pull/3542 Found some bugs when running intergration tests locally again, and the PR is an attempt to fix them: - When updating/creating HTTPS/SRV records, Vercel API only reads from the corresponding struct (either `srv` or `https`). If we provide a `value`, the Vercel API will reject with an error. - The PR makes `Value` "nil-able", and sets `Value` to nil when dealing with `SRV` or `HTTPS` records. - When updating a record, currently, we treat the empty SVC param as omitting the field. But with Vercel's API, omitting a field means not updating the field. We need to explicitly make the field an empty string to create/update an empty SVC param, and the PR does that. - Vercel implements an unknown `ech=` parameter validation process for HTTPS records. The validation process is unknown, undocumented, thus I can't implement a `rejectif` for `AuditRecord`. - Let's make this a known caveat, describe it in the provider docs, skip these intergration tests, and move on. Please tag this PR w/ `provider-VERCEL`.
This commit is contained in:
parent
7dc81bb4b1
commit
6153e3bac9
4 changed files with 47 additions and 6 deletions
|
|
@ -144,3 +144,13 @@ Vercel does not allow the record type to be changed after creation. If you try t
|
||||||
### Minimum TTL
|
### Minimum TTL
|
||||||
|
|
||||||
Vercel enforces a minimum TTL of 60 seconds (1 minute) for all records. We will always silently override the TTL to 60 seconds if you try to set a lower TTL.
|
Vercel enforces a minimum TTL of 60 seconds (1 minute) for all records. We will always silently override the TTL to 60 seconds if you try to set a lower TTL.
|
||||||
|
|
||||||
|
### HTTPS Record ECH Base64 Validation
|
||||||
|
|
||||||
|
Currently, Vercel does implements IETF's "Bootstrapping TLS Encrypted ClientHello with DNS Service Bindings" draft. However, Vercel also implements a validation process for the `ech` parameter in the `HTTPS` records, and will reject the request with the following error message if Vercel considers the `ech` value is invalid:
|
||||||
|
|
||||||
|
```
|
||||||
|
Invalid base64 string: [input] (key: ech)
|
||||||
|
```
|
||||||
|
|
||||||
|
The detail of Vercel's validation process is unknown, thus we can not support static validation for `dnscontrol check` or `dnscontrol preview`. You should use `ech=` with caution.
|
||||||
|
|
|
||||||
|
|
@ -292,6 +292,18 @@ func makeTests() []*TestGroup {
|
||||||
|
|
||||||
testgroup("Ech",
|
testgroup("Ech",
|
||||||
requires(providers.CanUseHTTPS),
|
requires(providers.CanUseHTTPS),
|
||||||
|
not(
|
||||||
|
// Last tested in 2025-12-04. Turns out that Vercel implements an unknown validation
|
||||||
|
// on the `ech` parameter, and our dummy base64 string are being rejected with:
|
||||||
|
//
|
||||||
|
// Invalid base64 string: [our base64] (key: ech)
|
||||||
|
//
|
||||||
|
// Since Vercel's validation process is unknown and not documented, we can't implement
|
||||||
|
// a rejectif within auditrecord to reject them statically.
|
||||||
|
//
|
||||||
|
// Let's just ignore ECH test for Vercel for now.
|
||||||
|
"VERCEL",
|
||||||
|
),
|
||||||
tc("Create a HTTPS record", https("@", 1, "example.com.", "alpn=h2,h3")),
|
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("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("Ignore the ECH key while changing other values", https("@", 1, "example.net.", "port=80 ech=IGNORE")),
|
||||||
|
|
|
||||||
|
|
@ -89,12 +89,13 @@ func (c *vercelProvider) ListDNSRecords(ctx context.Context, domain string) ([]D
|
||||||
type httpsRecord struct {
|
type httpsRecord struct {
|
||||||
Priority int64 `json:"priority"`
|
Priority int64 `json:"priority"`
|
||||||
Target string `json:"target"`
|
Target string `json:"target"`
|
||||||
Params string `json:"params,omitempty"`
|
Params string `json:"params"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// createDNSRecordRequest embeds the official SDK request but adds HTTPS support
|
// createDNSRecordRequest embeds the official SDK request but adds HTTPS support
|
||||||
type createDNSRecordRequest struct {
|
type createDNSRecordRequest struct {
|
||||||
vercelClient.CreateDNSRecordRequest
|
vercelClient.CreateDNSRecordRequest
|
||||||
|
Value *string `json:"value,omitempty"`
|
||||||
HTTPS *httpsRecord `json:"https,omitempty"`
|
HTTPS *httpsRecord `json:"https,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -317,7 +317,7 @@ func toVercelCreateRequest(domain string, rc *models.RecordConfig) (createDNSRec
|
||||||
}
|
}
|
||||||
req.Name = name
|
req.Name = name
|
||||||
req.Type = rc.Type
|
req.Type = rc.Type
|
||||||
req.Value = rc.GetTargetField()
|
req.Value = ptrString(rc.GetTargetField())
|
||||||
req.TTL = int64(rc.TTL)
|
req.TTL = int64(rc.TTL)
|
||||||
req.Comment = ""
|
req.Comment = ""
|
||||||
|
|
||||||
|
|
@ -331,17 +331,24 @@ func toVercelCreateRequest(domain string, rc *models.RecordConfig) (createDNSRec
|
||||||
Port: int64(rc.SrvPort),
|
Port: int64(rc.SrvPort),
|
||||||
Target: rc.GetTargetField(),
|
Target: rc.GetTargetField(),
|
||||||
}
|
}
|
||||||
req.Value = "" // SRV uses the SRV struct, not Value
|
// When dealing with SRV records, we must not set the Value fields,
|
||||||
|
// otherwise the API throws an error:
|
||||||
|
// bad_request - Invalid request: should NOT have additional property `value`
|
||||||
|
req.Value = nil
|
||||||
case "TXT":
|
case "TXT":
|
||||||
req.Value = rc.GetTargetTXTJoined()
|
req.Value = ptrString(rc.GetTargetTXTJoined())
|
||||||
case "HTTPS":
|
case "HTTPS":
|
||||||
req.HTTPS = &httpsRecord{
|
req.HTTPS = &httpsRecord{
|
||||||
Priority: int64(rc.SvcPriority),
|
Priority: int64(rc.SvcPriority),
|
||||||
Target: rc.GetTargetField(),
|
Target: rc.GetTargetField(),
|
||||||
Params: rc.SvcParams,
|
Params: rc.SvcParams,
|
||||||
}
|
}
|
||||||
|
// When dealing with HTTPS records, we must not set the Value fields,
|
||||||
|
// otherwise the API throws an error:
|
||||||
|
// bad_request - Invalid request: should NOT have additional property `value`.
|
||||||
|
req.Value = nil
|
||||||
case "CAA":
|
case "CAA":
|
||||||
req.Value = fmt.Sprintf(`%v %s "%s"`, rc.CaaFlag, rc.CaaTag, rc.GetTargetField())
|
req.Value = ptrString(fmt.Sprintf(`%v %s "%s"`, rc.CaaFlag, rc.CaaTag, rc.GetTargetField()))
|
||||||
}
|
}
|
||||||
|
|
||||||
return req, nil
|
return req, nil
|
||||||
|
|
@ -373,7 +380,10 @@ func toVercelUpdateRequest(rc *models.RecordConfig) (updateDNSRecordRequest, err
|
||||||
Port: ptrInt64(int64(rc.SrvPort)),
|
Port: ptrInt64(int64(rc.SrvPort)),
|
||||||
Target: &value,
|
Target: &value,
|
||||||
}
|
}
|
||||||
req.Value = nil // SRV uses the SRV struct, not Value
|
// When dealing with SRV records, we must not set the Value fields,
|
||||||
|
// otherwise the API throws an error:
|
||||||
|
// bad_request - Invalid request: should NOT have additional property `value`
|
||||||
|
req.Value = nil
|
||||||
case "TXT":
|
case "TXT":
|
||||||
txtValue := rc.GetTargetTXTJoined()
|
txtValue := rc.GetTargetTXTJoined()
|
||||||
req.Value = &txtValue
|
req.Value = &txtValue
|
||||||
|
|
@ -383,6 +393,10 @@ func toVercelUpdateRequest(rc *models.RecordConfig) (updateDNSRecordRequest, err
|
||||||
Target: rc.GetTargetField(),
|
Target: rc.GetTargetField(),
|
||||||
Params: rc.SvcParams,
|
Params: rc.SvcParams,
|
||||||
}
|
}
|
||||||
|
// When dealing with HTTPS records, we must not set the Value fields,
|
||||||
|
// otherwise the API throws an error:
|
||||||
|
// bad_request - Invalid request: should NOT have additional property `value`.
|
||||||
|
req.Value = nil
|
||||||
case "CAA":
|
case "CAA":
|
||||||
value := fmt.Sprintf(`%v %s "%s"`, rc.CaaFlag, rc.CaaTag, rc.GetTargetField())
|
value := fmt.Sprintf(`%v %s "%s"`, rc.CaaFlag, rc.CaaTag, rc.GetTargetField())
|
||||||
req.Value = &value
|
req.Value = &value
|
||||||
|
|
@ -395,3 +409,7 @@ func toVercelUpdateRequest(rc *models.RecordConfig) (updateDNSRecordRequest, err
|
||||||
func ptrInt64(v int64) *int64 {
|
func ptrInt64(v int64) *int64 {
|
||||||
return &v
|
return &v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ptrString(v string) *string {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue