On 08/12/15 08:56, Petr Spacek wrote:
On 7.12.2015 14:41, David Kupka wrote:
+def is_host_resolvable(fqdn):
+ if not isinstance(fqdn, DNSName):
+ fqdn = DNSName(fqdn)
+ for rdtype in (rdatatype.A, rdatatype.AAAA):
+ try:
+ resolver.query(fqdn.make_absolute(), rdtype)
+ except DNSException:
+ continue
+ else:
+ return True
+
+ return False
NACK, you are re-introducing duplicate function which was removed in
498471e4aed1367b72cd74d15811d0584a6ee268.
Please amend the patch ASAP to use new verify_host_resolvable() function so I
can test it and get it into 4.3.
Updated patches attached.
--
David Kupka
From 6927ea57fe73ad9dfd64d432aa18fd7b3ecda084 Mon Sep 17 00:00:00 2001
From: David Kupka <dku...@redhat.com>
Date: Wed, 2 Dec 2015 13:17:13 +0000
Subject: [PATCH] dns: do not add (forward)zone if it is already resolvable.
Check if the zone user wants to add is already resolvable and refuse to
create it if yes. --skip-overlap-check and --force options suppress this check.
https://fedorahosted.org/freeipa/ticket/5087
---
API.txt | 7 +++--
ipalib/plugins/dns.py | 32 ++++++++++++++++---
ipapython/ipautil.py | 87 +++++++++++++++++++++++++++++++++++++++++++++++++--
3 files changed, 117 insertions(+), 9 deletions(-)
diff --git a/API.txt b/API.txt
index 60c98c31aa85d6c8879cd145f3d84188d4fea5b7..3a9fb65a386a2a6529b8cd241642446c135471f2 100644
--- a/API.txt
+++ b/API.txt
@@ -959,7 +959,7 @@ output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDA
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: PrimaryKey('value', None, None)
command: dnsforwardzone_add
-args: 1,8,3
+args: 1,9,3
arg: DNSNameParam('idnsname', attribute=True, cli_name='name', multivalue=False, only_absolute=True, primary_key=True, required=True)
option: Str('addattr*', cli_name='addattr', exclude='webui')
option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
@@ -968,6 +968,7 @@ option: StrEnum('idnsforwardpolicy', attribute=True, cli_name='forward_policy',
option: Str('name_from_ip', attribute=False, cli_name='name_from_ip', multivalue=False, required=False)
option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
option: Str('setattr*', cli_name='setattr', exclude='webui')
+option: Flag('skip_overlap_check', autofill=True, default=False)
option: Str('version?', exclude='webui')
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
@@ -1366,7 +1367,7 @@ output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDA
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: PrimaryKey('value', None, None)
command: dnszone_add
-args: 1,26,3
+args: 1,28,3
arg: DNSNameParam('idnsname', attribute=True, cli_name='name', multivalue=False, only_absolute=True, primary_key=True, required=True)
option: Str('addattr*', cli_name='addattr', exclude='webui')
option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
@@ -1393,6 +1394,8 @@ option: Str('name_from_ip', attribute=False, cli_name='name_from_ip', multivalue
option: Str('nsec3paramrecord', attribute=True, cli_name='nsec3param_rec', multivalue=False, pattern='^\\d+ \\d+ \\d+ (([0-9a-fA-F]{2})+|-)$', required=False)
option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
option: Str('setattr*', cli_name='setattr', exclude='webui')
+option: Flag('skip_nameserver_check', autofill=True, default=False)
+option: Flag('skip_overlap_check', autofill=True, default=False)
option: Str('version?', exclude='webui')
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py
index 67947360eb207de31ed114bb630705c409b2f9a9..9cad9cfb8b4175cc92778b2df057621ca055e58f 100644
--- a/ipalib/plugins/dns.py
+++ b/ipalib/plugins/dns.py
@@ -53,8 +53,7 @@ from ipalib.util import (normalize_zonemgr,
validate_dnssec_zone_forwarder_step1,
validate_dnssec_zone_forwarder_step2,
verify_host_resolvable)
-
-from ipapython.ipautil import CheckedIPAddress
+from ipapython.ipautil import CheckedIPAddress, check_zone_overlap
from ipapython.dnsutil import DNSName
if six.PY3:
@@ -2121,6 +2120,13 @@ class DNSZoneBase(LDAPObject):
class DNSZoneBase_add(LDAPCreate):
+ takes_options = LDAPCreate.takes_options + (
+ Flag('skip_overlap_check',
+ doc=_('Force DNS zone creation even if it will overlap with '
+ 'an existing zone.')
+ ),
+ )
+
has_output_params = LDAPCreate.has_output_params + dnszone_output_params
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
@@ -2140,6 +2146,12 @@ class DNSZoneBase_add(LDAPCreate):
entry_attrs['idnszoneactive'] = 'TRUE'
+ if not options['skip_overlap_check']:
+ try:
+ check_zone_overlap(keys[-1])
+ except ValueError as e:
+ raise errors.InvocationError(e.message)
+
return dn
@@ -2696,8 +2708,13 @@ class dnszone_add(DNSZoneBase_add):
takes_options = DNSZoneBase_add.takes_options + (
Flag('force',
- label=_('Force'),
- doc=_('Force DNS zone creation even if nameserver is not resolvable.'),
+ doc=_('Force DNS zone creation even if nameserver is not '
+ 'resolvable. (Deprecated)'),
+ ),
+
+ Flag('skip_nameserver_check',
+ doc=_('Force DNS zone creation even if nameserver is not '
+ 'resolvable.'),
),
# Deprecated
@@ -2721,6 +2738,11 @@ class dnszone_add(DNSZoneBase_add):
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
assert isinstance(dn, DN)
+ if options.get('force'):
+ if options.get('skip_nameserver_check'):
+ ("'force' is deprecated.")
+ options['skip_nameserver_check'] = True
+
dn = super(dnszone_add, self).pre_callback(
ldap, dn, entry_attrs, attrs_list, *keys, **options)
@@ -2736,7 +2758,7 @@ class dnszone_add(DNSZoneBase_add):
error=_("Nameserver for reverse zone cannot be a relative DNS name"))
# verify if user specified server is resolvable
- if not options['force']:
+ if not options['skip_nameserver_check']:
check_ns_rec_resolvable(keys[0], entry_attrs['idnssoamname'],
self.log)
# show warning about --name-server option
diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py
index 89047b2e8ea16d14a6634e551c49abe240c54009..3ce61e31872ad69ca6ec366b67799b4adca8a63b 100644
--- a/ipapython/ipautil.py
+++ b/ipapython/ipautil.py
@@ -39,7 +39,7 @@ import grp
from contextlib import contextmanager
from dns import resolver, rdatatype
-from dns.exception import DNSException
+from dns.exception import DNSException, Timeout
import six
from six.moves import input
from six.moves import urllib
@@ -50,6 +50,7 @@ from ipapython import config
from ipaplatform.paths import paths
from ipapython.dn import DN
from ipapython.dnsutil import DNSName
+from ipalib.util import normalize_zone
SHARE_DIR = paths.USR_SHARE_IPA_DIR
PLUGINS_SHARE_DIR = paths.IPA_PLUGINS
@@ -240,7 +241,6 @@ def template_file(infilename, vars):
with open(infilename) as f:
return template_str(f.read(), vars)
-
def copy_template_file(infilename, outfilename, vars):
"""Copy a file, performing template substitutions"""
txt = template_file(infilename, vars)
@@ -925,6 +925,89 @@ def host_exists(host):
else:
return True
+def check_zone_overlap(zone, raise_on_timeout=True):
+ if not isinstance(zone, DNSName):
+ zone = DNSName(normalize_zone(zone))
+
+ try:
+ containing_zone = resolver.zone_for_name(zone)
+ except Timeout as e:
+ msg = ("DNS check for domain %s failed: %s. Please make sure that the "
+ "domain is properly delegated to this IPA server." % (zone, e))
+ if raise_on_timeout:
+ raise ValueError(msg)
+ else:
+ root_logger.warning(msg)
+ return
+
+ if containing_zone == zone:
+ try:
+ ns = [ans.to_text() for ans in resolver.query(zone, 'NS')]
+ except DNSException as e:
+ root_logger.debug("Failed to resolve nameserver(s) for domain"
+ " {0}: {1}".format(zone, e))
+ ns = []
+
+ msg = u"DNS zone {0} already exists in DNS".format(zone)
+ if ns:
+ msg += u" and is handled by server(s): {0}".format(', '.join(ns))
+ raise ValueError(msg)
+
+def check_reverse_zone_overlap(zone, raise_on_timeout=True):
+ automatic_empty_zones = [
+ # RFC 1918
+ "10.IN-ADDR.ARPA", "16.172.IN-ADDR.ARPA", "17.172.IN-ADDR.ARPA",
+ "18.172.IN-ADDR.ARPA", "19.172.IN-ADDR.ARPA", "20.172.IN-ADDR.ARPA",
+ "21.172.IN-ADDR.ARPA", "22.172.IN-ADDR.ARPA", "23.172.IN-ADDR.ARPA",
+ "24.172.IN-ADDR.ARPA", "25.172.IN-ADDR.ARPA", "26.172.IN-ADDR.ARPA",
+ "27.172.IN-ADDR.ARPA", "28.172.IN-ADDR.ARPA", "29.172.IN-ADDR.ARPA",
+ "30.172.IN-ADDR.ARPA", "31.172.IN-ADDR.ARPA", "168.192.IN-ADDR.ARPA",
+ # RFC 6598
+ "64.100.IN-ADDR.ARPA", "65.100.IN-ADDR.ARPA", "66.100.IN-ADDR.ARPA",
+ "67.100.IN-ADDR.ARPA", "68.100.IN-ADDR.ARPA", "69.100.IN-ADDR.ARPA",
+ "70.100.IN-ADDR.ARPA", "71.100.IN-ADDR.ARPA", "72.100.IN-ADDR.ARPA",
+ "73.100.IN-ADDR.ARPA", "74.100.IN-ADDR.ARPA", "75.100.IN-ADDR.ARPA",
+ "76.100.IN-ADDR.ARPA", "77.100.IN-ADDR.ARPA", "78.100.IN-ADDR.ARPA",
+ "79.100.IN-ADDR.ARPA", "80.100.IN-ADDR.ARPA", "81.100.IN-ADDR.ARPA",
+ "82.100.IN-ADDR.ARPA", "83.100.IN-ADDR.ARPA", "84.100.IN-ADDR.ARPA",
+ "85.100.IN-ADDR.ARPA", "86.100.IN-ADDR.ARPA", "87.100.IN-ADDR.ARPA",
+ "88.100.IN-ADDR.ARPA", "89.100.IN-ADDR.ARPA", "90.100.IN-ADDR.ARPA",
+ "91.100.IN-ADDR.ARPA", "92.100.IN-ADDR.ARPA", "93.100.IN-ADDR.ARPA",
+ "94.100.IN-ADDR.ARPA", "95.100.IN-ADDR.ARPA", "96.100.IN-ADDR.ARPA",
+ "97.100.IN-ADDR.ARPA", "98.100.IN-ADDR.ARPA", "99.100.IN-ADDR.ARPA",
+ "100.100.IN-ADDR.ARPA", "101.100.IN-ADDR.ARPA",
+ "102.100.IN-ADDR.ARPA", "103.100.IN-ADDR.ARPA",
+ "104.100.IN-ADDR.ARPA", "105.100.IN-ADDR.ARPA",
+ "106.100.IN-ADDR.ARPA", "107.100.IN-ADDR.ARPA",
+ "108.100.IN-ADDR.ARPA", "109.100.IN-ADDR.ARPA",
+ "110.100.IN-ADDR.ARPA", "111.100.IN-ADDR.ARPA",
+ "112.100.IN-ADDR.ARPA", "113.100.IN-ADDR.ARPA",
+ "114.100.IN-ADDR.ARPA", "115.100.IN-ADDR.ARPA",
+ "116.100.IN-ADDR.ARPA", "117.100.IN-ADDR.ARPA",
+ "118.100.IN-ADDR.ARPA", "119.100.IN-ADDR.ARPA",
+ "120.100.IN-ADDR.ARPA", "121.100.IN-ADDR.ARPA",
+ "122.100.IN-ADDR.ARPA", "123.100.IN-ADDR.ARPA",
+ "124.100.IN-ADDR.ARPA", "125.100.IN-ADDR.ARPA",
+ "126.100.IN-ADDR.ARPA", "127.100.IN-ADDR.ARPA",
+ # RFC 5735 and RFC 5737
+ "0.IN-ADDR.ARPA", "127.IN-ADDR.ARPA", "254.169.IN-ADDR.ARPA",
+ "2.0.192.IN-ADDR.ARPA", "100.51.198.IN-ADDR.ARPA",
+ "113.0.203.IN-ADDR.ARPA", "255.255.255.255.IN-ADDR.ARPA",
+ # Local IPv6 Unicast Addresses
+ "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA",
+ "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA",
+ # LOCALLY ASSIGNED LOCAL ADDRESS SCOPE
+ "D.F.IP6.ARPA", "8.E.F.IP6.ARPA", "9.E.F.IP6.ARPA", "A.E.F.IP6.ARPA",
+ "B.E.F.IP6.ARPA",
+ # Example Prefix, RFC 3849.
+ "8.B.D.0.1.0.0.2.IP6.ARPA",
+ # RFC 7534
+ "EMPTY.AS112.ARPA",
+ ]
+ if zone in automatic_empty_zones:
+ return
+ check_zone_overlap(zone, raise_on_timeout=raise_on_timeout)
+
def get_ipa_basedn(conn):
"""
Get base DN of IPA suffix in given LDAP server.
--
2.5.0
From b211e48bdf567c1688f51d1f2533de7288e032d8 Mon Sep 17 00:00:00 2001
From: David Kupka <dku...@redhat.com>
Date: Wed, 2 Dec 2015 14:20:50 +0000
Subject: [PATCH] dns: Check if domain already exists.
Raise an error when the domain already exists. This can be overriden using
--force or --allow-zone-overlap options.
https://fedorahosted.org/freeipa/ticket/3681
---
install/tools/ipa-dns-install | 3 +
ipaserver/install/bindinstance.py | 128 +++++++++++++++++++++++--------------
ipaserver/install/dns.py | 20 ++++++
ipaserver/install/server/common.py | 16 +++++
4 files changed, 118 insertions(+), 49 deletions(-)
diff --git a/install/tools/ipa-dns-install b/install/tools/ipa-dns-install
index bdaffd30b2554c100dc29bd18e0474165d05c024..4fd75670f044a3ccf1e22463b5f2dd77515172d3 100755
--- a/install/tools/ipa-dns-install
+++ b/install/tools/ipa-dns-install
@@ -57,6 +57,9 @@ def parse_options():
help="The reverse DNS zone to use. This option can be used multiple times")
parser.add_option("--no-reverse", dest="no_reverse", action="store_true",
default=False, help="Do not create new reverse DNS zone")
+ parser.add_option("--allow-zone-overlap", dest="allow_zone_overlap",
+ action="store_true", default=False, help="Create DNS "
+ "zone even if it already exists")
parser.add_option("--no-dnssec-validation", dest="no_dnssec_validation", action="store_true",
default=False, help="Disable DNSSEC validation")
parser.add_option("--dnssec-master", dest="dnssec_master", action="store_true",
diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
index 6bfde83de600df43e3430299100565e554a80583..93f9a49ca674dba6e4c586e9734c5805fc1df1b5 100644
--- a/ipaserver/install/bindinstance.py
+++ b/ipaserver/install/bindinstance.py
@@ -46,7 +46,7 @@ from ipalib.util import (validate_zonemgr_str, normalize_zonemgr,
get_dns_forward_zone_update_policy, get_dns_reverse_zone_update_policy,
normalize_zone, get_reverse_zone_default, zone_is_reverse,
validate_dnssec_global_forwarder, DNSSECSignatureMissingError,
- EDNS0UnsupportedError, UnresolvableRecordError)
+ EDNS0UnsupportedError, UnresolvableRecordError, verify_host_resolvable)
from ipalib.constants import CACERT
if six.PY3:
@@ -278,15 +278,23 @@ def find_reverse_zone(ip_address, api=api):
return None
-def read_reverse_zone(default, ip_address):
+def read_reverse_zone(default, ip_address, allow_zone_overlap=False):
while True:
zone = ipautil.user_input("Please specify the reverse zone name", default=default)
if not zone:
return None
- if verify_reverse_zone(zone, ip_address):
- break
- else:
- print("Invalid reverse zone %s for IP address %s" % (zone, ip_address))
+ if not verify_reverse_zone(zone, ip_address):
+ root_logger.error("Invalid reverse zone %s for IP address %s"
+ % (zone, ip_address))
+ continue
+ if not allow_zone_overlap:
+ try:
+ ipautil.check_reverse_zone_overlap(zone, raise_on_timeout=False)
+ except ValueError as e:
+ root_logger.error("Reverse zone %s will not be used: %s"
+ % (zone, e))
+ continue
+ break
return normalize_zone(zone)
@@ -407,43 +415,64 @@ def zonemgr_callback(option, opt_str, value, parser):
parser.values.zonemgr = value
def check_reverse_zones(ip_addresses, reverse_zones, options, unattended, search_reverse_zones=False):
- reverse_asked = False
-
ret_reverse_zones = []
- # check that there is IP address in every reverse zone
- if reverse_zones:
- for rz in reverse_zones:
- for ip in ip_addresses:
- if verify_reverse_zone(rz, ip):
- ret_reverse_zones.append(normalize_zone(rz))
- break
- else:
- # no ip matching reverse zone found
- sys.exit("There is no IP address matching reverse zone %s." % rz)
- if not options.no_reverse:
- # check that there is reverse zone for every IP
+
+ if not options.no_reverse and not reverse_zones:
+ if unattended:
+ options.no_reverse = True
+ else:
+ options.no_reverse = not create_reverse()
+
+ # shortcut
+ if options.no_reverse:
+ return ret_reverse_zones
+
+ # verify zones passed in options
+ for rz in reverse_zones:
+ # is there a IP for this zone
for ip in ip_addresses:
- if search_reverse_zones and find_reverse_zone(str(ip)):
- # reverse zone is already in LDAP
- continue
- for rz in ret_reverse_zones:
- if verify_reverse_zone(rz, ip):
- # reverse zone was entered by user
- break
+ if verify_reverse_zone(rz, ip):
+ break
+ else:
+ msg = ("Reverse zone %s will not be used: There is no IP "
+ "address matching reverse zone %s." % (rz, rz))
+ if options.unattended:
+ sys.exit(msg)
else:
- # no reverse zone for ip found
- if not reverse_asked:
- if not unattended and not reverse_zones:
- # user did not specify reverse_zone nor no_reverse
- options.no_reverse = not create_reverse()
- if options.no_reverse:
- # user decided not to create reverse zone
- return []
- reverse_asked = True
- rz = get_reverse_zone_default(str(ip))
- if not unattended:
- rz = read_reverse_zone(rz, str(ip))
- ret_reverse_zones.append(rz)
+ root_logger.warning(msg)
+
+ # isn't the zone managed by someone else
+ if not options.allow_zone_overlap:
+ try:
+ ipautil.check_reverse_zone_overlap(rz)
+ except ValueError as e:
+ msg = "Reverse zone %s will not be used: %s" % (rz, e)
+ if options.unattended:
+ sys.exit(msg)
+ else:
+ root_logger.warning(msg)
+ continue
+
+ ret_reverse_zones.append(normalize_zone(rz))
+
+ # check that there is reverse zone for every IP
+ for ip in ip_addresses:
+ if search_reverse_zones and find_reverse_zone(str(ip)):
+ # reverse zone is already in LDAP
+ continue
+ for rz in ret_reverse_zones:
+ if verify_reverse_zone(rz, ip):
+ # reverse zone was entered by user
+ break
+ else:
+ # no reverse zone for ip found
+ if not unattended:
+ if ipautil.user_input("Do you want to create reverse zone for "
+ "IP %s" % ip, True):
+ rz = get_reverse_zone_default(str(ip))
+ rz = read_reverse_zone(rz, str(ip),
+ options.allow_zone_overlap)
+ ret_reverse_zones.append(rz)
return ret_reverse_zones
@@ -817,18 +846,19 @@ class BindInstance(service.Service):
api=self.api)
if not dns_zone_exists(zone, self.api):
- # add DNS domain for host first
- root_logger.debug(
- "Host domain (%s) is different from DNS domain (%s)!" % (
- zone, self.domain))
- root_logger.debug("Add DNS zone for host first.")
-
- add_zone(zone, self.zonemgr, dns_backup=self.dns_backup,
- ns_hostname=self.fqdn, force=True, api=self.api)
+ # check if master hostname is resolvable
+ try:
+ verify_host_resolvable(fqdn, root_logger)
+ except errors.DNSNotARecordError():
+ root_logger.warning("Master FQDN (%s) is not resolvable.",
+ fqdn)
# Add forward and reverse records to self
for addr in addrs:
- add_fwd_rr(zone, host, addr, api=self.api)
+ try:
+ add_fwd_rr(zone, host, addr, self.api)
+ except errors.NotFound as e:
+ pass
reverse_zone = find_reverse_zone(addr, self.api)
if reverse_zone:
diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py
index 258bf5dbe46e2167e07a62127c7fd8fd4be23ee6..276dae2778eb15e01f65f3ab05b4e4fc9bdcffe4 100644
--- a/ipaserver/install/dns.py
+++ b/ipaserver/install/dns.py
@@ -13,11 +13,13 @@ from subprocess import CalledProcessError
from ipalib import api
from ipalib import errors
+from ipalib import util
from ipaplatform.paths import paths
from ipaplatform.constants import constants
from ipaplatform import services
from ipapython import ipautil
from ipapython import sysrestore
+from ipapython import dnsutil
from ipapython.dn import DN
from ipapython.ipa_log_manager import root_logger
from ipapython.ipaldap import AUTOBIND_ENABLED
@@ -106,6 +108,24 @@ def install_check(standalone, replica, options, hostname):
raise RuntimeError("Integrated DNS requires '%s' package" %
constants.IPA_DNS_PACKAGE_NAME)
+ domain = dnsutil.DNSName(util.normalize_zone(api.env.domain))
+ try:
+ ipautil.check_zone_overlap(domain, raise_on_timeout=False)
+ except ValueError as e:
+ if options.force or options.allow_zone_overlap:
+ root_logger.warning(e.message)
+ else:
+ raise e
+
+ for reverse_zone in options.reverse_zones:
+ try:
+ ipautil.check_reverse_zone_overlap(reverse_zone)
+ except ValueError as e:
+ if options.force or options.allow_zone_overlap:
+ root_logger.warning(e.message)
+ else:
+ raise e
+
if standalone:
print("==============================================================================")
print("This program will setup DNS for the FreeIPA Server.")
diff --git a/ipaserver/install/server/common.py b/ipaserver/install/server/common.py
index 1c161120bcb22d384afcd9a5c462645cfcc753a8..0e2b3d9da0314cf500cd91faf22e6259ea031459 100644
--- a/ipaserver/install/server/common.py
+++ b/ipaserver/install/server/common.py
@@ -10,6 +10,8 @@ from ipapython.install import common, core
from ipapython.install.core import Knob
from ipalib.util import validate_domain_name
from ipaserver.install import bindinstance
+from ipapython.ipautil import check_reverse_zone_overlap, check_zone_overlap
+from ipapython.dnsutil import DNSName
VALID_SUBJECT_ATTRS = ['st', 'o', 'ou', 'dnqualifier', 'c',
'serialnumber', 'l', 'title', 'sn', 'givenname',
@@ -171,6 +173,11 @@ class BaseServerDNS(common.Installable, core.Group, core.Composite):
description="Do not add any DNS forwarders, use root servers instead",
)
+ allow_zone_overlap = Knob(
+ bool, False,
+ description="Create DNS zone even if it already exists",
+ )
+
reverse_zones = Knob(
(list, str), [],
description=("The reverse DNS zone to use. This option can be used "
@@ -179,6 +186,12 @@ class BaseServerDNS(common.Installable, core.Group, core.Composite):
cli_metavar='REVERSE_ZONE',
)
+ @reverse_zones.validator
+ def reverse_zones(self, values):
+ if not self.allow_zone_overlap:
+ for zone in values:
+ check_reverse_zone_overlap(zone)
+
no_reverse = Knob(
bool, False,
description="Do not create new reverse DNS zone",
@@ -255,6 +268,8 @@ class BaseServer(common.Installable, common.Interactive, core.Composite):
@domain_name.validator
def domain_name(self, value):
validate_domain_name(value)
+ if self.setup_dns and not self.dns.allow_zone_overlap: # pylint: disable=no-member
+ check_zone_overlap(value)
dm_password = Knob(
str, None,
@@ -452,6 +467,7 @@ class BaseServer(common.Installable, common.Interactive, core.Composite):
self.no_forwarders = self.dns.no_forwarders
self.reverse_zones = self.dns.reverse_zones
self.no_reverse = self.dns.no_reverse
+ self.allow_zone_overlap = self.dns.allow_zone_overlap
self.no_dnssec_validation = self.dns.no_dnssec_validation
self.dnssec_master = self.dns.dnssec_master
self.disable_dnssec_master = self.dns.disable_dnssec_master
--
2.5.0
--
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code