1
0
mirror of https://github.com/StackExchange/dnscontrol.git synced 2024-05-11 05:55:12 +00:00
Patrick Gaskin 70ce16ff23 Fix handling of SRV records with no target (indicated by ".")
According to the RFC, the way to indicate that a SRV has no target is to set the target to ".".  Some providers do not handle this, or the API returns "" instead of ".".  This situation is now tested in the integration tests and all providers (that support this) have been fixed.



* Cloudflare: Fix decoding empty SRV target (fixes #561)

SRV records with empty (".") targets are now returned as false by
the API, which breaks Unmarshaling it into a string.

* Use custom type for Cloudflare SRV target

Rewrote the SRV target decoding to use a custom type for (un)marshaling, as
Cloudflare returns false for null targets, but it requires a single period
for giving it one. The target code has also been made more flexible to future
API changes with additional normalization.

This has been tested with record creation, deletion, and update and works
as of 2019-11-05.

* DigitalOcean: Fix target FQDN for null targets

Without this, dnscontrol thinks an update is needed (.. != .) even
when the SRV target is correct.

* DNSimple: Fix parsing of null SRV target

DNSimple only returns two fields when the target is null.

* NameDotCom: Add note about not supporting null SRV targets, skip test

* DNSimple: Do not append a . unless we have all three parts

Signed-off-by: Amelia Aronsohn <squirrel@wearing.black>

* Regenerated provider matrix
2019-11-14 11:25:20 -05:00

69 lines
2.4 KiB
Go

package models
import (
"strconv"
"strings"
"github.com/pkg/errors"
)
// SetTargetSRV sets the SRV fields.
func (rc *RecordConfig) SetTargetSRV(priority, weight, port uint16, target string) error {
rc.SrvPriority = priority
rc.SrvWeight = weight
rc.SrvPort = port
rc.SetTarget(target)
if rc.Type == "" {
rc.Type = "SRV"
}
if rc.Type != "SRV" {
panic("assertion failed: SetTargetSRV called when .Type is not SRV")
}
return nil
}
// setTargetSRVIntAndStrings is like SetTargetSRV but accepts priority as an int, the other parameters as strings.
func (rc *RecordConfig) setTargetSRVIntAndStrings(priority uint16, weight, port, target string) (err error) {
var i64weight, i64port uint64
if i64weight, err = strconv.ParseUint(weight, 10, 16); err == nil {
if i64port, err = strconv.ParseUint(port, 10, 16); err == nil {
return rc.SetTargetSRV(priority, uint16(i64weight), uint16(i64port), target)
}
}
return errors.Wrap(err, "SRV value too big for uint16")
}
// SetTargetSRVStrings is like SetTargetSRV but accepts all parameters as strings.
func (rc *RecordConfig) SetTargetSRVStrings(priority, weight, port, target string) (err error) {
var i64priority uint64
if i64priority, err = strconv.ParseUint(priority, 10, 16); err == nil {
return rc.setTargetSRVIntAndStrings(uint16(i64priority), weight, port, target)
}
return errors.Wrap(err, "SRV value too big for uint16")
}
// SetTargetSRVPriorityString is like SetTargetSRV but accepts priority as an
// uint16 and the rest of the values joined in a string that needs to be parsed.
// This is a helper function that comes in handy when a provider re-uses the MX preference
// field as the SRV priority.
func (rc *RecordConfig) SetTargetSRVPriorityString(priority uint16, s string) error {
part := strings.Fields(s)
switch len(part) {
case 3:
return rc.setTargetSRVIntAndStrings(priority, part[0], part[1], part[2])
case 2:
return rc.setTargetSRVIntAndStrings(priority, part[0], part[1], ".")
default:
return errors.Errorf("SRV value does not contain 3 fields: (%#v)", s)
}
}
// SetTargetSRVString is like SetTargetSRV but accepts one big string to be parsed.
func (rc *RecordConfig) SetTargetSRVString(s string) error {
part := strings.Fields(s)
if len(part) != 4 {
return errors.Errorf("SRC value does not contain 4 fields: (%#v)", s)
}
return rc.SetTargetSRVStrings(part[0], part[1], part[2], part[3])
}