When a new DNS zone is being created a local hostname is set as a
nameserver of the new zone. However, when the zone is created
during ipa-replica-prepare, the the current master/replica doesn't
have to be an IPA server with DNS support. This would lead to DNS
zones with incorrect NS records as they wouldn't point to a valid
name server.

Now, a list of all master servers with DNS support is retrieved
during DNS zone creation and added as NS records for a new DNS
zone.

https://fedorahosted.org/freeipa/ticket/1261

>From a85204dd4f956fb2e80e29b2b9bb6feafa502a53 Mon Sep 17 00:00:00 2001
From: Martin Kosek <mko...@redhat.com>
Date: Wed, 1 Jun 2011 14:51:06 +0200
Subject: [PATCH] Improve DNS zone creation

When a new DNS zone is being created a local hostname is set as a
nameserver of the new zone. However, when the zone is created
during ipa-replica-prepare, the the current master/replica doesn't
have to be an IPA server with DNS support. This would lead to DNS
zones with incorrect NS records as they wouldn't point to a valid
name server.

Now, a list of all master servers with DNS support is retrieved
during DNS zone creation and added as NS records for a new DNS
zone.

https://fedorahosted.org/freeipa/ticket/1261
---
 install/tools/ipa-replica-prepare |    8 ++---
 ipalib/plugins/dns.py             |   20 +++++++++++
 ipaserver/install/bindinstance.py |   67 ++++++++++++++++++++++++++++---------
 3 files changed, 74 insertions(+), 21 deletions(-)

diff --git a/install/tools/ipa-replica-prepare b/install/tools/ipa-replica-prepare
index df44934de8c15cf88ea7fc313a108c963197d3e4..c773ecb8b61a9c61ac818309bcbb9e1080d767dd 100755
--- a/install/tools/ipa-replica-prepare
+++ b/install/tools/ipa-replica-prepare
@@ -430,8 +430,6 @@ def main():
         ip_address = str(ip)
         ip_prefixlen = ip.prefixlen
 
-        ns_ip_address = resolve_host(api.env.host)
-
         if ip.defaultnet:
             revzone = ip.reverse_dns
             if ip.version == 4:
@@ -450,10 +448,10 @@ def main():
             if prefix > 0:
                 ip_prefixlen = prefix
             else:
-                add_reverse_zone(ip_address, ip_prefixlen, ns_ip_address)
+                add_reverse_zone(ip_address, ip_prefixlen)
 
-        zone = add_zone(domain, nsaddr=ns_ip_address)
-        add_fwd_rr(zone, name, ip_address)
+        add_zone(domain)
+        add_fwd_rr(domain, name, ip_address)
         add_ptr_rr(ip_address, ip_prefixlen, replica_fqdn)
 
 try:
diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py
index 42ca498c9920b6b66b78083e6eca9f58921ae228..cc2e6e548fee33e5a89ab5e29b12df6aef239c38 100644
--- a/ipalib/plugins/dns.py
+++ b/ipalib/plugins/dns.py
@@ -105,6 +105,7 @@ from ipalib import Flag, Int, List, Str, StrEnum
 from ipalib.plugins.baseldap import *
 from ipalib import _, ngettext
 from ipapython import dnsclient
+from ldap import explode_dn
 
 # supported resource record types
 _record_types = (
@@ -559,6 +560,25 @@ class dnsrecord(LDAPObject):
             cliname = attr
         return cliname
 
+    def get_dns_masters(self):
+        ldap = self.api.Backend.ldap2
+        base_dn = 'cn=masters,cn=ipa,cn=etc,%s' % self.api.env.basedn
+        ldap_filter = '(&(objectClass=ipaConfigObject)(cn=DNS))'
+        dns_masters = []
+
+        try:
+            entries = ldap.find_entries(filter=ldap_filter, base_dn=base_dn)[0]
+
+            for entry in entries:
+                master_dn = entry[0]
+                if master_dn.startswith('cn='):
+                    master = explode_dn(master_dn)[1].replace('cn=','')
+                    dns_masters.append(master)
+        except errors.NotFound:
+            return []
+
+        return dns_masters
+
 api.register(dnsrecord)
 
 
diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
index fc6519d960f8dbead699a9fcaa7b0046c9999856..2f897b423f30b6b08127783f00adcd6352f09ca4 100644
--- a/ipaserver/install/bindinstance.py
+++ b/ipaserver/install/bindinstance.py
@@ -28,6 +28,7 @@ import ldap
 import service
 from ipaserver import ipaldap
 from ipaserver.install.dsinstance import realm_to_serverid
+from ipaserver.install.installutils import resolve_host
 from ipapython import sysrestore
 from ipapython import ipautil
 
@@ -125,39 +126,69 @@ def dns_zone_exists(name):
     else:
         return True
 
-def add_zone(name, zonemgr=None, dns_backup=None, nsaddr=None, update_policy=None):
-    if not update_policy:
+def add_zone(name, zonemgr=None, dns_backup=None, ns_hostname=None, ns_ip_address=None,
+       update_policy=None):
+    if update_policy is None:
         update_policy = "grant %(realm)s krb5-self * A; grant %(realm)s krb5-self * AAAA;" % dict(realm=api.env.realm)
 
+    if ns_hostname is None:
+        # automatically retrieve list of DNS masters
+        dns_masters = api.Object.dnsrecord.get_dns_masters()
+        if not dns_masters:
+            raise errors.NotFound("No IPA server with DNS support found!")
+        ns_main = dns_masters.pop(0)
+        ns_replicas = dns_masters
+        ns_ip_address = resolve_host(ns_main)
+    else:
+        ns_main = ns_hostname
+        ns_replicas = []
+
     try:
         api.Command.dnszone_add(unicode(name),
-                                idnssoamname=unicode(api.env.host+"."),
+                                idnssoamname=unicode(ns_main+'.'),
                                 idnssoarname=unicode(zonemgr),
-                                ip_address=unicode(nsaddr),
+                                ip_address=unicode(ns_ip_address),
                                 idnsallowdynupdate=True,
                                 idnsupdatepolicy=unicode(update_policy))
     except (errors.DuplicateEntry, errors.EmptyModlist):
         pass
 
-    add_rr(name, "@", "NS", api.env.host+'.', dns_backup, force=True)
-    return name
+    nameservers = ns_replicas + [ns_main]
+    for hostname in nameservers:
+        add_ns_rr(name, hostname, dns_backup=None, force=True)
 
-def add_reverse_zone(ip_address, ip_prefixlen, ns_ip_address, update_policy=None, dns_backup=None):
+
+def add_reverse_zone(ip_address, ip_prefixlen, ns_hostname=None, ns_ip_address=None,
+        ns_replicas=[], update_policy=None, dns_backup=None):
     zone, name = get_reverse_zone(ip_address, ip_prefixlen)
-    if not update_policy:
+    if update_policy is None:
         update_policy = "grant %s krb5-subdomain %s. PTR;" % (api.env.realm, zone)
+
+    if ns_hostname is None:
+        # automatically retrieve list of DNS masters
+        dns_masters = api.Object.dnsrecord.get_dns_masters()
+        if not dns_masters:
+            raise errors.NotFound("No IPA server with DNS support found!")
+        ns_main = dns_masters.pop(0)
+        ns_replicas = dns_masters
+        ns_ip_address = resolve_host(ns_main)
+    else:
+        ns_main = ns_hostname
+        ns_replicas = []
+
     try:
         api.Command.dnszone_add(unicode(zone),
-                                idnssoamname=unicode(api.env.host+"."),
+                                idnssoamname=unicode(ns_main+'.'),
                                 idnsallowdynupdate=True,
                                 ip_address=unicode(ns_ip_address),
                                 idnsupdatepolicy=unicode(update_policy))
     except (errors.DuplicateEntry, errors.EmptyModlist):
         pass
 
-    add_rr(zone, "@", "NS", api.env.host+".", dns_backup, force=True)
+    nameservers = ns_replicas + [ns_main]
+    for hostname in nameservers:
+        add_ns_rr(zone, hostname, dns_backup=None, force=True)
 
-    return zone
 
 def add_rr(zone, name, type, rdata, dns_backup=None, **kwargs):
     addkw = { '%srecord' % str(type.lower()) : unicode(rdata) }
@@ -180,6 +211,10 @@ def add_ptr_rr(ip_address, ip_prefixlen, fqdn, dns_backup=None):
     zone, name = get_reverse_zone(ip_address, ip_prefixlen)
     add_rr(zone, name, "PTR", fqdn+".", dns_backup)
 
+def add_ns_rr(zone, hostname, dns_backup=None, force=True):
+    add_rr(zone, "@", "NS", hostname+'.', dns_backup=dns_backup,
+            force=force)
+
 def del_rr(zone, name, type, rdata):
     delkw = { '%srecord' % str(type.lower()) : unicode(rdata) }
     try:
@@ -367,11 +402,11 @@ class BindInstance(service.Service):
         self._ldap_mod("dns.ldif", self.sub_dict)
 
     def __setup_zone(self):
-        zone = add_zone(self.domain, self.zonemgr,
-                        self.dns_backup, self.ip_address)
+        add_zone(self.domain, self.zonemgr, dns_backup=self.dns_backup,
+                ns_hostname=api.env.host, ns_ip_address=self.ip_address)
 
     def __add_self_ns(self):
-        add_rr(self.domain, "@", "NS", api.env.host+'.', self.dns_backup, force=True)
+        add_ns_rr(self.domain, api.env.host, self.dns_backup, force=True)
 
     def __add_self(self):
         zone = self.domain
@@ -400,8 +435,8 @@ class BindInstance(service.Service):
             add_ptr_rr(self.ip_address, self.ip_prefixlen, self.fqdn)
 
     def __setup_reverse_zone(self):
-        add_reverse_zone(self.ip_address, self.ip_prefixlen, self.ip_address,
-                dns_backup=self.dns_backup)
+        add_reverse_zone(self.ip_address, self.ip_prefixlen, ns_hostname=api.env.host,
+                ns_ip_address=self.ip_address, dns_backup=self.dns_backup)
 
     def __setup_principal(self):
         dns_principal = "DNS/" + self.fqdn + "@" + self.realm
-- 
1.7.5.2

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to