Skip to content

Support for OVH "SPF" custom records is broken #339

@bgandon

Description

@bgandon

Symptom: dnscontrol crashes when seeing an SPF record at OVH.

$ dnscontrol preview --config zones/emaple-dot-org.js 
******************** Domain: example.org
----- Getting nameservers from: ovh
----- DNS Provider: ovh...panic: unparsable record received from ovh: Unknown rtype (SPF) when parsing ("v=spf1 include:mx.ovh.com ~all") domain=(example.org)

goroutine 1 [running]:
github.com/StackExchange/dnscontrol/providers/ovh.nativeToRecord(0xc4204cc500, 0xc4205a0c00, 0xd, 0xc4202a6000)
	/Users/benjamin/workspace/go/src/github.com/StackExchange/dnscontrol/providers/ovh/ovhProvider.go:160 +0x256
github.com/StackExchange/dnscontrol/providers/ovh.(*ovhProvider).GetDomainCorrections(0xc420354080, 0xc420052000, 0x3, 0xc420052000, 0x1, 0x0, 0x0)
	/Users/benjamin/workspace/go/src/github.com/StackExchange/dnscontrol/providers/ovh/ovhProvider.go:98 +0x16a
github.com/StackExchange/dnscontrol/commands.run(0x7fff5fbff2ec, 0x1a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19f3dba, 0xa, 0x0, ...)
	/Users/benjamin/workspace/go/src/github.com/StackExchange/dnscontrol/commands/previewPush.go:129 +0x3d7
github.com/StackExchange/dnscontrol/commands.Preview(0x7fff5fbff2ec, 0x1a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19f3dba, 0xa, 0x0, ...)
	/Users/benjamin/workspace/go/src/github.com/StackExchange/dnscontrol/commands/previewPush.go:81 +0x74
github.com/StackExchange/dnscontrol/commands.glob..func3.1(0xc42009af20, 0x0, 0xc42009af20)
	/Users/benjamin/workspace/go/src/github.com/StackExchange/dnscontrol/commands/previewPush.go:25 +0x4e
github.com/StackExchange/dnscontrol/vendor/github.com/urfave/cli.HandleAction(0x1853c20, 0xc42014c010, 0xc42009af20, 0x0, 0xc4202082a0)
	/Users/benjamin/workspace/go/src/github.com/StackExchange/dnscontrol/vendor/github.com/urfave/cli/app.go:501 +0xd2
github.com/StackExchange/dnscontrol/vendor/github.com/urfave/cli.Command.Run(0x19f1731, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1a16fef, 0x4e, 0x0, ...)
	/Users/benjamin/workspace/go/src/github.com/StackExchange/dnscontrol/vendor/github.com/urfave/cli/command.go:165 +0x4bb
github.com/StackExchange/dnscontrol/vendor/github.com/urfave/cli.(*App).Run(0xc420122700, 0xc420010140, 0x4, 0x4, 0x0, 0x0)
	/Users/benjamin/workspace/go/src/github.com/StackExchange/dnscontrol/vendor/github.com/urfave/cli/app.go:259 +0x740
github.com/StackExchange/dnscontrol/commands.Run(0xc4200174c0, 0x14, 0x1792062)
	/Users/benjamin/workspace/go/src/github.com/StackExchange/dnscontrol/commands/commands.go:50 +0x18a
main.main()
	/Users/benjamin/workspace/go/src/github.com/StackExchange/dnscontrol/main.go:18 +0x34

Here is the (obfuscated) DNSControl zone file:

var REG_OVH = NewRegistrar("ovh", "OVH");
var REG_NONE = NewRegistrar('none', 'NONE');
var OVH = NewDnsProvider("ovh", "OVH");

D("example.org", OVH, DnsProvider(OVH),
    DefaultTTL('3600'),

    // NAMESERVER('@', 'dns200.anycast.me.'),
    // NAMESERVER('@', 'ns200.anycast.me.'),

    MX('@', 1, 'redirect.ovh.net.'),
    MX('www', 1, 'redirect.ovh.net.'),

    // no-op conversion from existing SPF record
    TXT('@', 'v=spf1 include:mx.ovh.com ~all', TTL(600)),

    SRV('_autodiscover._tcp', 0, 0, 443, 'mailconfig.ovh.net.'),
    SRV('_imaps._tcp',        0, 0, 993, 'ssl0.ovh.net.'),
    SRV('_submission._tcp',   0, 0, 465, 'ssl0.ovh.net.'),
    CNAME('autoconfig', 'mailconfig.ovh.net.'),
    CNAME('autodiscover', 'mailconfig.ovh.net.'),
    CNAME('ftp', 'example.org.'),
    CNAME('imap', 'ssl0.ovh.net.'),
    CNAME('mail', 'ssl0.ovh.net.'),
    A('openvpn', '52.166.201.7'),
    CNAME('pop3', 'ssl0.ovh.net.'),
    CNAME('smtp', 'ssl0.ovh.net.'),

    A('@', '213.186.33.5'),
    TXT('@', '1|www.example.org'),
    A('www', '213.186.33.5'),
    TXT('www', 'l|fr'),
    TXT('www', '3|welcome')
)

Here is the (obfuscated) state of the DNS zone at OVH. It's actually an empty standard DNS zone, as created by default at OVH.

$TTL 3600
@	IN SOA dns200.anycast.me. tech.ovh.net. (2018032000 86400 3600 3600000 300)
                          IN NS     dns200.anycast.me.
                          IN NS     ns200.anycast.me.
                          IN MX 1   redirect.ovh.net.
                          IN A      213.186.33.5
                          IN TXT    "1|www.example.org"
                      600 IN TXT    "v=spf1 include:mx.ovh.com ~all"
_autodiscover._tcp        IN SRV    0 0 443 mailconfig.ovh.net.
_imaps._tcp               IN SRV    0 0 993 ssl0.ovh.net.
_submission._tcp          IN SRV    0 0 465 ssl0.ovh.net.
autoconfig                IN CNAME  mailconfig.ovh.net.
autodiscover              IN CNAME  mailconfig.ovh.net.
ftp                       IN CNAME  example.org.
imap                      IN CNAME  ssl0.ovh.net.
mail                      IN CNAME  ssl0.ovh.net.
openvpn                   IN A      52.166.201.7
pop3                      IN CNAME  ssl0.ovh.net.
smtp                      IN CNAME  ssl0.ovh.net.
www                       IN MX 1   redirect.ovh.net.
www                       IN A      213.186.33.5
www                       IN TXT    "l|fr"
www                       IN TXT    "3|welcome"

Analysis: in the nativeToRecord() function, the hack-ish conversion from SPF to TXT is too late, because PopulateFromString() panics before this.

func nativeToRecord(r *Record, origin string) *models.RecordConfig {
	// ... //
	rtype := r.FieldType
	rec.SetLabel(r.SubDomain, origin)
	if err := rec.PopulateFromString(rtype, r.Target, origin); err != nil {
		panic(errors.Wrap(err, "unparsable record received from ovh"))
	}

	// ovh uses a custom type for SPF and DKIM
	if rtype == "SPF" || rtype == "DKIM" {
		rec.Type = "TXT"
	}

	// ... //
}

When I try to fix the above code, moving the if rtype == "SPF" statement upwards, then the zone diff behaves surprisingly: dnscontrol preview wants to delete every existing records, and then re-create exactly the same ones.

As a workaround, it is possible to replace the SPF record by a TXT record, using the OVH Web Control Panel. But it would be cool that dnscontrol support for those SPF record again. :)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions