summaryrefslogtreecommitdiffstats
path: root/ipalib/plugins/dns.py
diff options
context:
space:
mode:
authorMartin Basti <mbasti@redhat.com>2014-04-10 12:26:37 +0200
committerMartin Kosek <mkosek@redhat.com>2014-06-03 15:55:32 +0200
commit5b88b39499f6d6ea46efa55b1a50353fc3c17fe7 (patch)
treed068abbd045a96b37510c24dfad5013fe1e90848 /ipalib/plugins/dns.py
parenta4d3d01f3f89c40c5ff18dafdecf88422effc447 (diff)
downloadfreeipa-5b88b39499f6d6ea46efa55b1a50353fc3c17fe7.tar.gz
freeipa-5b88b39499f6d6ea46efa55b1a50353fc3c17fe7.tar.xz
freeipa-5b88b39499f6d6ea46efa55b1a50353fc3c17fe7.zip
Modified record and zone class to support IDN
* Records data are always returned as string * Attributes idnsname, idnssoamname, idnssoarname are returned as * DNSName, with option --raw as string * option --raw returns all IDN domains punycoded Part of ticket: IPA should allow internationalized domain names https://fedorahosted.org/freeipa/ticket/3169 Reviewed-By: Jan Cholasta <jcholast@redhat.com>
Diffstat (limited to 'ipalib/plugins/dns.py')
-rw-r--r--ipalib/plugins/dns.py404
1 files changed, 307 insertions, 97 deletions
diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py
index 5fcc309da..27caf851b 100644
--- a/ipalib/plugins/dns.py
+++ b/ipalib/plugins/dns.py
@@ -26,6 +26,7 @@ import re
import dns.name
import dns.exception
import dns.resolver
+import encodings.idna
from ipalib.request import context
from ipalib import api, errors, output
@@ -606,10 +607,19 @@ class DNSRecord(Str):
return None
return tuple(values)
- def _part_values_to_string(self, values, index):
+ def _part_values_to_string(self, values, index, idna=True):
self._validate_parts(values)
- return u" ".join(super(DNSRecord, self)._convert_scalar(v, index) \
- for v in values if v is not None)
+ parts = []
+ for v in values:
+ if v is None:
+ continue
+ elif isinstance(v, DNSName) and idna:
+ v = v.ToASCII()
+ elif not isinstance(v, unicode):
+ v = unicode(v)
+ parts.append(v)
+
+ return u" ".join(parts)
def get_parts_from_kw(self, kw, raise_on_none=True):
part_names = tuple(self.part_name_format % (self.rrtype.lower(), part.name) \
@@ -1230,9 +1240,13 @@ class NSECRecord(DNSRecord):
return (values[0], tuple(values[1:]))
- def _part_values_to_string(self, values, index):
+ def _part_values_to_string(self, values, index, idna=True):
self._validate_parts(values)
- values_flat = [values[0],] # add "next" part
+ if idna:
+ val = values[0].ToASCII()
+ else:
+ val = unicode(values[0])
+ values_flat = [val, ] # add "next" part
types = values[1]
if not isinstance(types, (list, tuple)):
types = [types,]
@@ -1511,7 +1525,7 @@ def check_ns_rec_resolvable(zone, name):
# this is a DNS name relative to the zone
name = name.derelativize(zone.make_absolute())
try:
- return api.Command['dns_resolve'](name)
+ return api.Command['dns_resolve'](unicode(name))
except errors.NotFound:
raise errors.NotFound(
reason=_('Nameserver \'%(host)s\' does not have a corresponding '
@@ -1537,6 +1551,133 @@ dnszone_output_params = (
),
)
+
+def _convert_to_idna(value):
+ """
+ Function converts a unicode value to idna, without extra validation.
+ If conversion fails, None is returned
+ """
+ assert isinstance(value, unicode)
+
+ try:
+ idna_val = value
+ start_dot = u''
+ end_dot = u''
+ if idna_val.startswith(u'.'):
+ idna_val = idna_val[1:]
+ start_dot = u'.'
+ if idna_val.endswith(u'.'):
+ idna_val = idna_val[:-1]
+ end_dot = u'.'
+ idna_val = encodings.idna.nameprep(idna_val)
+ idna_val = re.split(r'(?<!\\)\.', idna_val)
+ idna_val = u'%s%s%s' % (start_dot,
+ u'.'.join(encodings.idna.ToASCII(x)
+ for x in idna_val),
+ end_dot)
+ return idna_val
+ except Exception:
+ pass
+ return None
+
+def _create_idn_filter(cmd, ldap, *args, **options):
+ term = args[-1]
+ if term:
+ #include idna values to search
+ term_idna = _convert_to_idna(term)
+ if term_idna and term != term_idna:
+ term = (term, term_idna)
+
+ search_kw = {}
+ attr_extra_filters = []
+
+ for attr, value in cmd.args_options_2_entry(**options).iteritems():
+ if not isinstance(value, list):
+ value = [value]
+ for i, v in enumerate(value):
+ if isinstance(v, DNSName):
+ value[i] = v.ToASCII()
+ elif attr in map_names_to_records:
+ record = map_names_to_records[attr]
+ parts = record._get_part_values(v)
+ if parts is None:
+ value[i] = v
+ continue
+ try:
+ value[i] = record._part_values_to_string(parts, None)
+ except errors.ValidationError:
+ value[i] = v
+
+ #create MATCH_ANY filter for multivalue
+ if len(value) > 1:
+ f = ldap.make_filter({attr: value}, rules=ldap.MATCH_ANY)
+ attr_extra_filters.append(f)
+ else:
+ search_kw[attr] = value
+
+ if cmd.obj.search_attributes:
+ search_attrs = cmd.obj.search_attributes
+ else:
+ search_attrs = cmd.obj.default_attributes
+ if cmd.obj.search_attributes_config:
+ config = ldap.get_ipa_config()
+ config_attrs = config.get(cmd.obj.search_attributes_config, [])
+ if len(config_attrs) == 1 and (isinstance(config_attrs[0],
+ basestring)):
+ search_attrs = config_attrs[0].split(',')
+
+ search_kw['objectclass'] = cmd.obj.object_class
+ attr_filter = ldap.make_filter(search_kw, rules=ldap.MATCH_ALL)
+ if attr_extra_filters:
+ #combine filter if there is any idna value
+ attr_extra_filters.append(attr_filter)
+ attr_filter = ldap.combine_filters(attr_extra_filters,
+ rules=ldap.MATCH_ALL)
+
+ search_kw = {}
+ for a in search_attrs:
+ search_kw[a] = term
+ term_filter = ldap.make_filter(search_kw, exact=False)
+
+ member_filter = cmd.get_member_filter(ldap, **options)
+
+ filter = ldap.combine_filters(
+ (term_filter, attr_filter, member_filter), rules=ldap.MATCH_ALL
+ )
+ return filter
+
+
+map_names_to_records = {"%srecord" % record.rrtype.lower(): record for record
+ in _dns_records if record.supported}
+
+def _records_idn_postprocess(record, **options):
+ for attr in record.keys():
+ attr = attr.lower()
+ try:
+ param = map_names_to_records[attr]
+ except KeyError:
+ continue
+ if not isinstance(param, DNSRecord):
+ continue
+
+ part_params = param.get_parts()
+ rrs = []
+ for dnsvalue in record[attr]:
+ parts = param._get_part_values(dnsvalue)
+ if parts is None:
+ continue
+ parts = list(parts)
+ try:
+ for (i, p) in enumerate(parts):
+ if isinstance(part_params[i], DNSNameParam):
+ parts[i] = DNSName(p)
+ rrs.append(param._part_values_to_string(parts, None,
+ idna=options.get('raw', False)))
+ except (errors.ValidationError, errors.ConversionError):
+ rrs.append(dnsvalue)
+ record[attr] = rrs
+
+
class dnszone(LDAPObject):
"""
DNS Zone, container for resource records.
@@ -1713,57 +1854,50 @@ class dnszone(LDAPObject):
def get_dn(self, *keys, **options):
zone = keys[-1]
+ assert isinstance(zone, DNSName)
+ assert zone.is_absolute()
+ zone = zone.ToASCII()
+
+ #try first relative name, a new zone has to be added as absolute
+ #otherwise ObjectViolation is raised
+ zone = zone[:-1]
dn = super(dnszone, self).get_dn(zone, **options)
try:
self.backend.get_entry(dn, [''])
except errors.NotFound:
- if zone.endswith(u'.'):
- zone = zone[:-1]
- else:
- zone = zone + u'.'
- test_dn = super(dnszone, self).get_dn(zone, **options)
-
- try:
- dn = self.backend.get_entry(test_dn, ['']).dn
- except errors.NotFound:
- pass
+ zone = u"%s." % zone
+ dn = super(dnszone, self).get_dn(zone, **options)
return dn
def permission_name(self, zone):
- return u"Manage DNS zone %s" % zone
+ assert isinstance(zone, DNSName)
+ return u"Manage DNS zone %s" % zone.ToASCII()
def get_name_in_zone(self, zone, hostname):
"""
Get name of a record that is to be added to a new zone. I.e. when
we want to add record "ipa.lab.example.com" in a zone "example.com",
this function should return "ipa.lab". Returns None when record cannot
- be added to a zone
+ be added to a zone. Returns '@' when the hostname is the zone record.
"""
- if hostname == _dns_zone_record:
- # special case: @ --> zone name
- return hostname
-
- if hostname.endswith(u'.'):
- hostname = hostname[:-1]
- if zone.endswith(u'.'):
- zone = zone[:-1]
+ assert isinstance(zone, DNSName)
+ assert zone.is_absolute()
+ assert isinstance(hostname, DNSName)
- hostname_parts = hostname.split(u'.')
- zone_parts = zone.split(u'.')
+ if not hostname.is_absolute():
+ return hostname
- dns_name = list(hostname_parts)
- for host_part, zone_part in zip(reversed(hostname_parts),
- reversed(zone_parts)):
- if host_part != zone_part:
- return None
- dns_name.pop()
+ if hostname.is_subdomain(zone):
+ return hostname.relativize(zone)
- if not dns_name:
- # hostname is directly in zone itself
- return _dns_zone_record
+ return None
- return u'.'.join(dns_name)
+ def _rr_zone_postprocess(self, record, **options):
+ #Decode IDN ACE form to Unicode, raw records are passed directly from LDAP
+ if options.get('raw', False):
+ return
+ _records_idn_postprocess(record, **options)
api.register(dnszone)
@@ -1794,12 +1928,20 @@ class dnszone_add(LDAPCreate):
if kw.get('ip_address', None):
return
- zone = normalize_zone(kw['idnsname'])
- ns = kw['idnssoamname']
- relative_ns = not ns.endswith('.')
+ try:
+ zone = DNSName(kw['idnsname']).make_absolute()
+ except Exception, e:
+ raise errors.ValidationError(name='idnsname', error=unicode(e))
+
+ try:
+ ns = DNSName(kw['idnssoamname'])
+ except Exception, e:
+ raise errors.ValidationError(name='idnssoamname', error=unicode(e))
+
+ relative_ns = not ns.is_absolute()
ns_in_zone = self.obj.get_name_in_zone(zone, ns)
- if not zone_is_reverse(zone) and (relative_ns or ns_in_zone):
+ if not zone.is_reverse() and (relative_ns or ns_in_zone):
ip_address = self.Backend.textui.prompt(_(u'Nameserver IP address'))
kw['ip_address'] = ip_address
@@ -1819,15 +1961,14 @@ class dnszone_add(LDAPCreate):
error=_("Nameserver address is not a domain name"))
nameserver_ip_address = options.get('ip_address')
- normalized_zone = normalize_zone(keys[-1])
-
- if nameserver.endswith('.'):
+ zone = keys[-1]
+ if nameserver.is_absolute():
record_in_zone = self.obj.get_name_in_zone(keys[-1], nameserver)
else:
record_in_zone = nameserver
- if zone_is_reverse(normalized_zone):
- if not nameserver.endswith('.'):
+ if zone.is_reverse():
+ if not nameserver.is_absolute():
raise errors.ValidationError(name='name-server',
error=_("Nameserver for reverse zone cannot be "
"a relative DNS name"))
@@ -1835,7 +1976,8 @@ class dnszone_add(LDAPCreate):
raise errors.ValidationError(name='ip_address',
error=_("Nameserver DNS record is created for "
"for forward zones only"))
- elif nameserver_ip_address and nameserver.endswith('.') and not record_in_zone:
+ elif (nameserver_ip_address and nameserver.is_absolute() and
+ record_in_zone is None):
raise errors.ValidationError(name='ip_address',
error=_("Nameserver DNS record is created only for "
"nameservers in current zone"))
@@ -1852,7 +1994,7 @@ class dnszone_add(LDAPCreate):
nameserver_ip_address = options.get('ip_address')
if nameserver_ip_address:
nameserver = entry_attrs['idnssoamname'][0]
- if nameserver.endswith('.'):
+ if nameserver.is_absolute():
dns_record = self.obj.get_name_in_zone(keys[-1], nameserver)
else:
dns_record = nameserver
@@ -1864,14 +2006,16 @@ class dnszone_add(LDAPCreate):
# except for our own domain, forwarded zones and reverse zones
zone = keys[0]
- if (zone != api.env.domain
+ if (zone != DNSName(api.env.domain).make_absolute()
and not options.get('idnsforwarders')
- and not zone_is_reverse(zone)):
+ and not zone.is_reverse()):
try:
- api.Command['realmdomains_mod'](add_domain=zone, force=True)
- except errors.EmptyModlist:
+ api.Command['realmdomains_mod'](add_domain=unicode(zone),
+ force=True)
+ except (errors.EmptyModlist, errors.ValidationError):
pass
+ self.obj._rr_zone_postprocess(entry_attrs, **options)
return dn
api.register(dnszone_add)
@@ -1891,12 +2035,14 @@ class dnszone_del(LDAPDelete):
# Delete entry from realmdomains
# except for our own domain
- zone = keys[0]
+ zone = keys[0].make_absolute()
- if zone != api.env.domain:
+ if (zone != DNSName(api.env.domain).make_absolute() and
+ not zone.is_reverse()):
try:
- api.Command['realmdomains_mod'](del_domain=zone, force=True)
- except errors.AttrValueNotFound:
+ api.Command['realmdomains_mod'](del_domain=unicode(zone),
+ force=True)
+ except (errors.AttrValueNotFound, errors.ValidationError):
pass
return True
@@ -1918,11 +2064,16 @@ class dnszone_mod(LDAPUpdate):
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
nameserver = entry_attrs.get('idnssoamname')
- if nameserver and nameserver != _dns_zone_record and not options['force']:
+ if nameserver and not nameserver.is_empty() and not options['force']:
check_ns_rec_resolvable(keys[0], nameserver)
return dn
+ def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
+ self.obj._rr_zone_postprocess(entry_attrs, **options)
+ return dn
+
api.register(dnszone_mod)
@@ -1947,7 +2098,12 @@ class dnszone_find(LDAPSearch):
if 'idnsname' not in options:
options['idnsname'] = self.obj.params['idnsname'].get_default(**options)
del options['name_from_ip']
- return super(dnszone_find, self).args_options_2_entry(*args, **options)
+ search_kw = super(dnszone_find, self).args_options_2_entry(*args,
+ **options)
+ name = search_kw.get('idnsname')
+ if name:
+ search_kw['idnsname'] = [name, name.relativize(DNSName.root)]
+ return search_kw
takes_options = LDAPSearch.takes_options + (
Flag('forward_only',
@@ -1959,15 +2115,26 @@ class dnszone_find(LDAPSearch):
def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *args, **options):
assert isinstance(base_dn, DN)
+
+ filter = _create_idn_filter(self, ldap, *args, **options)
+
if options.get('forward_only', False):
search_kw = {}
- search_kw['idnsname'] = REVERSE_DNS_ZONES.keys()
- rev_zone_filter = ldap.make_filter(search_kw, rules=ldap.MATCH_NONE, exact=False,
- trailing_wildcard=False)
- filter = ldap.combine_filters((rev_zone_filter, filter), rules=ldap.MATCH_ALL)
+ search_kw['idnsname'] = [revzone.ToASCII() for revzone in
+ REVERSE_DNS_ZONES.keys()]
+ rev_zone_filter = ldap.make_filter(search_kw,
+ rules=ldap.MATCH_NONE,
+ exact=False,
+ trailing_wildcard=False)
+ filter = ldap.combine_filters((rev_zone_filter, filter),
+ rules=ldap.MATCH_ALL)
return (filter, base_dn, scope)
+ def post_callback(self, ldap, entries, truncated, *args, **options):
+ for entry_attrs in entries:
+ self.obj._rr_zone_postprocess(entry_attrs, **options)
+ return truncated
api.register(dnszone_find)
@@ -1977,6 +2144,11 @@ class dnszone_show(LDAPRetrieve):
has_output_params = LDAPRetrieve.has_output_params + dnszone_output_params
+ def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
+ self.obj._rr_zone_postprocess(entry_attrs, **options)
+ return dn
+
api.register(dnszone_show)
@@ -2139,21 +2311,24 @@ class dnsrecord(LDAPObject):
doc=_('Parse all raw DNS records and return them in a structured way'),
)
- def _idnsname_pre_callback(self, ldap, dn, entry_attrs, *keys, **options):
- if not self.is_pkey_zone_record(*keys):
- zone, addr = normalize_zone(keys[-2]), keys[-1]
- try:
- validate_domain_name(addr, allow_underscore=True, allow_slash=zone_is_reverse(zone))
- except ValueError, e:
- raise errors.ValidationError(name='idnsname', error=unicode(e))
-
def _nsrecord_pre_callback(self, ldap, dn, entry_attrs, *keys, **options):
assert isinstance(dn, DN)
nsrecords = entry_attrs.get('nsrecord')
if options.get('force', False) or nsrecords is None:
return
for nsrecord in nsrecords:
- check_ns_rec_resolvable(keys[0], nsrecord)
+ check_ns_rec_resolvable(keys[0], DNSName(nsrecord))
+
+ def _idnsname_pre_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
+ if keys[-1].is_absolute():
+ if keys[-1].is_subdomain(keys[-2]):
+ entry_attrs['idnsname'] = [keys[-1].relativize(keys[-2])]
+ elif not self.is_pkey_zone_record(*keys):
+ raise errors.ValidationError(name='idnsname',
+ error=unicode(_('out-of-zone data: record name must '
+ 'be a subdomain of the zone or a '
+ 'relative name')))
def _ptrrecord_pre_callback(self, ldap, dn, entry_attrs, *keys, **options):
assert isinstance(dn, DN)
@@ -2163,35 +2338,42 @@ class dnsrecord(LDAPObject):
zone = keys[-2]
if self.is_pkey_zone_record(*keys):
- addr = u''
+ addr = _dns_zone_record
else:
addr = keys[-1]
- zone = normalize_zone(zone)
-
zone_len = 0
for valid_zone in REVERSE_DNS_ZONES:
- if zone.endswith(valid_zone):
- zone = zone.replace(valid_zone,'')
+ if zone.is_subdomain(valid_zone):
+ zone = zone.relativize(valid_zone)
zone_name = valid_zone
zone_len = REVERSE_DNS_ZONES[valid_zone]
if not zone_len:
- allowed_zones = ', '.join(REVERSE_DNS_ZONES)
+ allowed_zones = ', '.join([unicode(revzone) for revzone in
+ REVERSE_DNS_ZONES.keys()])
raise errors.ValidationError(name='ptrrecord',
error=unicode(_('Reverse zone for PTR record should be a sub-zone of one the following fully qualified domains: %s') % allowed_zones))
- addr_len = len(addr.split('.')) if addr else 0
+ addr_len = len(addr.labels)
#Classless zones (0/25.0.0.10.in-addr.arpa.) -> skip check
#zone has to be checked without reverse domain suffix (in-addr.arpa.)
- if ('/' not in addr and '/' not in zone and
- '-' not in addr and '-' not in zone):
- ip_addr_comp_count = addr_len + len(zone.split('.'))
- if ip_addr_comp_count != zone_len:
- raise errors.ValidationError(name='ptrrecord',
- error=unicode(_('Reverse zone %(name)s requires exactly %(count)d IP address components, %(user_count)d given')
- % dict(name=zone_name, count=zone_len, user_count=ip_addr_comp_count)))
+ for sign in ('/', '-'):
+ for name in (zone, addr):
+ for label in name.labels:
+ if sign in label:
+ return
+
+ ip_addr_comp_count = addr_len + len(zone.labels)
+ if ip_addr_comp_count != zone_len:
+ raise errors.ValidationError(name='ptrrecord',
+ error=unicode(_('Reverse zone %(name)s requires exactly '
+ '%(count)d IP address components, '
+ '%(user_count)d given')
+ % dict(name=zone_name,
+ count=zone_len,
+ user_count=ip_addr_comp_count)))
def run_precallback_validators(self, dn, entry_attrs, *keys, **options):
assert isinstance(dn, DN)
@@ -2203,21 +2385,28 @@ class dnsrecord(LDAPObject):
rtype_cb(ldap, dn, entry_attrs, *keys, **options)
def is_pkey_zone_record(self, *keys):
+ assert isinstance(keys[-1], DNSName)
+ assert isinstance(keys[-2], DNSName)
idnsname = keys[-1]
- if idnsname == str(_dns_zone_record) or idnsname == ('%s.' % keys[-2]):
+ zonename = keys[-2]
+ if idnsname.is_empty() or idnsname == zonename:
return True
return False
def get_dn(self, *keys, **options):
if self.is_pkey_zone_record(*keys):
- dn = self.api.Object[self.parent_object].get_dn(*keys[:-1], **options)
+ parent_object = self.api.Object[self.parent_object]
+ dn = parent_object.get_dn(*keys[:-1], **options)
# zone must exist
ldap = self.api.Backend.ldap2
try:
ldap.get_entry(dn, [])
except errors.NotFound:
- self.api.Object['dnszone'].handle_not_found(keys[-2])
- return self.api.Object[self.parent_object].get_dn(*keys[:-1], **options)
+ parent_object.handle_not_found(*keys[:-1])
+ return dn
+ #Make RR name relative if possible
+ relative_name = keys[-1].relativize(keys[-2]).ToASCII()
+ keys = keys[:-1] + (relative_name,)
return super(dnsrecord, self).get_dn(*keys, **options)
def attr_to_cli(self, attr):
@@ -2292,10 +2481,20 @@ class dnsrecord(LDAPObject):
continue
for val_id, val in enumerate(values):
if val is not None:
- dnsentry[parts_params[val_id].name] = val
+ #decode IDN
+ if isinstance(parts_params[val_id], DNSNameParam):
+ dnsentry[parts_params[val_id].name] = \
+ _dns_name_to_string(val,
+ options.get('raw', False))
+ else:
+ dnsentry[parts_params[val_id].name] = val
record.setdefault('dnsrecords', []).append(dnsentry)
del record[attr]
+ elif not options.get('raw', False):
+ #Decode IDN ACE form to Unicode, raw records are passed directly from LDAP
+ _records_idn_postprocess(record, **options)
+
def get_rrparam_from_part(self, part_name):
"""
Get an instance of DNSRecord parameter that has part_name as its part.
@@ -2384,7 +2583,7 @@ class dnsrecord(LDAPObject):
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:
+ if rrattrs.get('nsrecord') and not keys[1].is_empty():
raise errors.ValidationError(name='dnamerecord',
error=_('DNAME record is not allowed to coexist with an '
'NS record except when located in a zone root '
@@ -2558,8 +2757,8 @@ class dnsrecord(LDAPObject):
Dict {(dns_domain, dns_name): entry_for_wait_for_modified_attrs}
'''
for entry_name, entry in entries.iteritems():
- dns_domain = dns.name.from_text(entry_name[0])
- dns_name = dns.name.from_text(entry_name[1], origin=dns_domain)
+ dns_domain = entry_name[0]
+ dns_name = entry_name[1].derelativize(dns_domain)
self.wait_for_modified_attrs(entry, dns_name, dns_domain)
api.register(dnsrecord)
@@ -2603,10 +2802,20 @@ class dnsrecord_add(LDAPCreate):
except errors.OptionError:
pass
+ try:
+ idnsname = DNSName(kw['idnsname'])
+ except Exception, e:
+ raise errors.ValidationError(name='idnsname', error=unicode(e))
+
+ try:
+ zonename = DNSName(kw['dnszoneidnsname'])
+ except Exception, e:
+ raise errors.ValidationError(name='dnszoneidnsname', error=unicode(e))
+
# check zone type
- if kw['idnsname'] == _dns_zone_record:
+ if idnsname.is_empty():
common_types = u', '.join(_zone_top_record_types)
- elif zone_is_reverse(kw['dnszoneidnsname']):
+ elif zonename.is_reverse():
common_types = u', '.join(_rev_top_record_types)
else:
common_types = u', '.join(_top_record_types)
@@ -3145,7 +3354,8 @@ class dnsrecord_find(LDAPSearch):
def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *args, **options):
assert isinstance(base_dn, DN)
- # include zone record (root entry) in the search
+
+ filter = _create_idn_filter(self, ldap, *args, **options)
return (filter, base_dn, ldap.SCOPE_SUBTREE)
def post_callback(self, ldap, entries, truncated, *args, **options):