Improve DNAME record validation

Extend DNS RR conflict check and forbid DNAME+NS combination unless
it is done in root DNS zone record.

Add tests to verify this enforced check.

https://fedorahosted.org/freeipa/ticket/3449
This commit is contained in:
Martin Kosek 2013-04-02 11:59:16 +02:00
parent 42c401a877
commit 30a1bc1f09
2 changed files with 102 additions and 12 deletions

View File

@ -2267,7 +2267,7 @@ class dnsrecord(LDAPObject):
processed.append(rrparam.name)
yield rrparam
def check_record_type_collisions(self, old_entry, entry_attrs):
def check_record_type_collisions(self, keys, old_entry, entry_attrs):
# Test that only allowed combination of record types was created
rrattrs = {}
if old_entry is not None:
@ -2298,6 +2298,24 @@ class dnsrecord(LDAPObject):
error=_('CNAME record is not allowed to coexist '
'with any other record (RFC 1034, section 3.6.2)'))
# DNAME record validation
try:
dnames = rrattrs['dnamerecord']
except KeyError:
pass
else:
if dnames is not None:
if len(dnames) > 1:
raise errors.ValidationError(name='dnamerecord',
error=_('only one DNAME record is allowed per name '
'(RFC 6672, section 2.4)'))
# DNAME must not coexist with CNAME, but this is already checked earlier
if rrattrs.get('nsrecord') and keys[1] != _dns_zone_record:
raise errors.ValidationError(name='dnamerecord',
error=_('DNAME record is not allowed to coexist with an '
'NS record except when located in a zone root '
'record (RFC 6672, section 2.3)'))
api.register(dnsrecord)
@ -2459,7 +2477,7 @@ class dnsrecord_add(LDAPCreate):
vals = list(entry_attrs[attr])
entry_attrs[attr] = list(set(old_entry.get(attr, []) + vals))
self.obj.check_record_type_collisions(old_entry, entry_attrs)
self.obj.check_record_type_collisions(keys, old_entry, entry_attrs)
return dn
def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs):
@ -2560,7 +2578,7 @@ class dnsrecord_mod(LDAPUpdate):
new_dnsvalue = [param._convert_scalar(modified_parts)]
entry_attrs[attr] = list(set(old_entry[attr] + new_dnsvalue))
self.obj.check_record_type_collisions(old_entry, entry_attrs)
self.obj.check_record_type_collisions(keys, old_entry, entry_attrs)
return dn
def execute(self, *keys, **options):

View File

@ -53,6 +53,8 @@ dnsrev2 = u'81'
dnsrev2_dn = DN(('idnsname',dnsrev2), revdnszone1_dn)
dnsrescname = u'testcnamerec'
dnsrescname_dn = DN(('idnsname',dnsrescname), dnszone1_dn)
dnsresdname = u'testdns-dname'
dnsresdname_dn = DN(('idnsname',dnsresdname), dnszone1_dn)
class test_dns(Declarative):
@ -223,15 +225,6 @@ class test_dns(Declarative):
},
),
dict(
desc='Delete zone %r' % dnszone2,
command=('dnszone_del', [dnszone2], {}),
expected={
'value': dnszone2,
'summary': None,
'result': {'failed': u''},
},
),
dict(
desc='Retrieve zone %r' % dnszone1,
@ -838,6 +831,85 @@ class test_dns(Declarative):
},
),
dict(
desc='Try to add multiple DNAME records to %r using dnsrecord_add' % (dnsresdname),
command=('dnsrecord_add', [dnszone1, dnsres1], {'dnamerecord':
[u'foo-1.example.com.', u'foo-2.example.com.']}),
expected=errors.ValidationError(name='dnamerecord',
error=u'only one DNAME record is allowed per name (RFC 6672, section 2.4)'),
),
dict(
desc='Try to add invalid DNAME record %r using dnsrecord_add' % (dnsresdname),
command=('dnsrecord_add', [dnszone1, dnsresdname], {'dnamerecord': u'-.example.com.'}),
expected=errors.ValidationError(name='target',
error=u'invalid domain-name: only letters, numbers, and - ' +
u'are allowed. DNS label may not start or end with -'),
),
dict(
desc='Add DNAME record to %r using dnsrecord_add' % (dnsresdname),
command=('dnsrecord_add', [dnszone1, dnsresdname],
{'dnamerecord': u'd.example.com.', 'arecord': u'10.0.0.1'}),
expected={
'value': dnsresdname,
'summary': None,
'result': {
'objectclass': objectclasses.dnsrecord,
'dn': dnsresdname_dn,
'idnsname': [dnsresdname],
'dnamerecord': [u'd.example.com.'],
'arecord': [u'10.0.0.1'],
},
},
),
dict(
desc='Try to add CNAME record to %r using dnsrecord_add' % (dnsresdname),
command=('dnsrecord_add', [dnszone1, dnsresdname], {'cnamerecord': u'foo-1.example.com.'}),
expected=errors.ValidationError(name='cnamerecord',
error=u'CNAME record is not allowed to coexist with any other '
u'record (RFC 1034, section 3.6.2)'),
),
dict(
desc='Try to add NS record to %r using dnsrecord_add' % (dnsresdname),
command=('dnsrecord_add', [dnszone1, dnsresdname],
{'nsrecord': u'%s.%s.' % (dnsres1, dnszone1)}),
expected=errors.ValidationError(name='dnamerecord',
error=u'DNAME record is not allowed to coexist with an NS '
u'record except when located in a zone root record (RFC 6672, section 2.3)'),
),
dict(
desc='Add NS+DNAME record to %r zone record using dnsrecord_add' % (dnszone2),
command=('dnsrecord_add', [dnszone2, u'@'],
{'dnamerecord': u'd.example.com.',
'nsrecord': dnszone1_mname}),
expected = {
'value': u'@',
'summary': None,
'result': {
'objectclass': objectclasses.dnszone,
'dnamerecord': [u'd.example.com.'],
'dn': dnszone2_dn,
'nsrecord': [dnszone2_mname, dnszone1_mname],
'idnsname': [u'@']
}
},
),
dict(
desc='Delete zone %r' % dnszone2,
command=('dnszone_del', [dnszone2], {}),
expected={
'value': dnszone2,
'summary': None,
'result': {'failed': u''},
},
),
dict(
desc='Try to add invalid KX record %r using dnsrecord_add' % (dnsres1),
command=('dnsrecord_add', [dnszone1, dnsres1], {'kxrecord': u'foo-1.example.com' }),