-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Attached is a patch that fixes the remaining IPv6 problems. Many were
testable on a v4 installation, like the host plugin changes. I only
verified the v6 reverse zone creation in bindinstance with ldapsearch so
far.

https://fedorahosted.org/freeipa/ticket/398
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iEYEARECAAYFAk1IVpEACgkQHsardTLnvCU6zgCfbGIORjtpz85kJN/BXU/YwLvO
ueAAoN/hkGEA8hBZj6IR3iZ6tv96oarm
=u6DS
-----END PGP SIGNATURE-----
From e9752923ee27bed10b5075cb83be165ff9f72c59 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhro...@redhat.com>
Date: Mon, 31 Jan 2011 15:30:43 +0100
Subject: [PATCH] IPv6 enhancements

* Make host-add, host-del and reverse zone creation IPv6 aware
* Make Bind listen on IPv6 interfaces, too

https://fedorahosted.org/freeipa/ticket/398
---
 install/share/bind.named.conf.template |    3 ++
 ipalib/plugins/host.py                 |   61 +++++++++++++++++++-------------
 ipaserver/install/bindinstance.py      |   33 +++++++++++------
 ipaserver/install/installutils.py      |    4 +-
 4 files changed, 62 insertions(+), 39 deletions(-)

diff --git a/install/share/bind.named.conf.template b/install/share/bind.named.conf.template
index 447c50c..71facba 100644
--- a/install/share/bind.named.conf.template
+++ b/install/share/bind.named.conf.template
@@ -1,4 +1,7 @@
 options {
+	// turns on IPv6 for port 53, IPv4 is on by default for all ifaces
+	listen-on-v6 {any;};
+
 	// Put files that named is allowed to write in the data/ directory:
 	directory "/var/named"; // the default
 	dump-file		"data/cache_dump.db";
diff --git a/ipalib/plugins/host.py b/ipalib/plugins/host.py
index d5c5174..9c49f25 100644
--- a/ipalib/plugins/host.py
+++ b/ipalib/plugins/host.py
@@ -85,6 +85,7 @@ from ipalib.plugins.service import set_certificate_attrs
 from ipalib.plugins.service import make_pem, check_writable_file
 from ipalib.plugins.service import write_certificate
 from ipalib.plugins.dns import dns_container_exists, _record_types
+from ipalib.plugins.dns import add_forward_record
 from ipalib import _, ngettext
 from ipalib import x509
 from ipapython.ipautil import ipa_generate_password
@@ -103,6 +104,32 @@ def validate_host(ugettext, fqdn):
         return _('Fully-qualified hostname required')
     return None
 
+def is_forward_record(zone, str_address):
+    addr = netaddr.IPAddress(str_address)
+    if addr.version == 4:
+        result = api.Command['dnsrecord_find'](zone, arecord=str_address)
+    elif addr.version == 6:
+        result = api.Command['dnsrecord_find'](zone, aaarecord=str_address)
+    else:
+        raise ValueError('Invalid address family')
+
+    return result['count'] > 0
+
+def remove_fwd_ptr(ipaddr, host, domain, recordtype):
+    api.log.debug('deleting ipaddr %s' % ipaddr)
+    revzone, revname = get_reverse_zone(ipaddr)
+    try:
+        delkw = { 'ptrrecord' : "%s.%s." % (host, domain) }
+        api.Command['dnsrecord_del'](revzone, revname, **delkw)
+    except errors.NotFound:
+        pass
+
+    try:
+        delkw = { recordtype : ipaddr }
+        api.Command['dnsrecord_del'](domain, host, **delkw)
+    except errors.NotFound:
+        pass
+
 host_output_params = (
     Flag('has_keytab',
         label=_('Keytab'),
@@ -309,8 +336,7 @@ class host_add(LDAPCreate):
                 except errors.NotFound:
                     pass
             else:
-                result = api.Command['dnsrecord_find'](domain, arecord=options['ip_address'])
-                if result['count'] > 0:
+                if is_forward_record(domain, options['ip_address']):
                     raise errors.DuplicateEntry(message=u'This IP address is already assigned.')
         if not options.get('force', False) and not 'ip_address' in options:
             util.validate_host_dns(self.log, keys[-1])
@@ -347,15 +373,8 @@ class host_add(LDAPCreate):
             if 'ip_address' in options and dns_container_exists(ldap):
                 parts = keys[-1].split('.')
                 domain = unicode('.'.join(parts[1:]))
-                if ':' in options['ip_address']:
-                    addkw = { 'aaaarecord' : options['ip_address'] }
-                else:
-                    addkw = { 'arecord' : options['ip_address'] }
-                try:
-                    api.Command['dnsrecord_add'](domain, parts[0], **addkw)
-                except errors.EmptyModlist:
-                    # the entry already exists and matches
-                    pass
+
+                add_forward_record(domain, parts[0], options['ip_address'])
 
                 if not options.get('no_reverse', False):
                     revzone, revname = get_reverse_zone(options['ip_address'])
@@ -444,24 +463,16 @@ class host_del(LDAPDelete):
             records = api.Command['dnsrecord_find'](domain, idnsname=parts[0])['result']
             for record in records:
                 if 'arecord' in record:
-                    ipaddr = record['arecord'][0]
-                    self.debug('deleting ipaddr %s' % ipaddr)
-                    revzone, revname = get_reverse_zone(ipaddr)
-                    try:
-                        delkw = { 'ptrrecord' : fqdn+'.' }
-                        api.Command['dnsrecord_del'](revzone, revname, **delkw)
-                    except errors.NotFound:
-                        pass
-                    try:
-                        delkw = { 'arecord' : ipaddr }
-                        api.Command['dnsrecord_del'](domain, parts[0], **delkw)
-                    except errors.NotFound:
-                        pass
+                    remove_fwd_ptr(record['arecord'][0], parts[0],
+                                   domain, 'arecord')
+                if 'aaaarecord' in record:
+                    remove_fwd_ptr(record['aaaarecord'][0], parts[0],
+                                   domain, 'aaaarecord')
                 else:
                     # Try to delete all other record types too
                     _attribute_types = [str('%srecord' % t.lower()) for t in _record_types]
                     for attr in _attribute_types:
-                        if attr != 'arecord' and attr in record:
+                        if attr not in ['arecord', 'aaaarecord'] and attr in record:
                             for i in xrange(len(record[attr])):
                                 if (record[attr][i].endswith(parts[0]) or
                                     record[attr][i].endswith(fqdn+'.')):
diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
index a2989e1..1f35dc1 100644
--- a/ipaserver/install/bindinstance.py
+++ b/ipaserver/install/bindinstance.py
@@ -21,6 +21,7 @@ import tempfile
 import os
 import pwd
 import logging
+import netaddr
 
 import installutils
 import ldap
@@ -97,11 +98,15 @@ def dns_container_exists(fqdn, suffix):
 
     return ret
 
-def get_reverse_zone(ip_address):
-    tmp = ip_address.split(".")
-    tmp.reverse()
-    name = tmp.pop(0)
-    zone = ".".join(tmp) + ".in-addr.arpa"
+def get_reverse_zone(ip_address_str):
+    ip = netaddr.IPAddress(ip_address_str)
+    if ip.version == 4:
+        name, dot, zone = ip.reverse_dns.partition('.')
+    elif ip.version == 6:
+        name = '.'.join(ip.reverse_dns.split('.')[:8])
+        zone = '.'.join(ip.reverse_dns.split('.')[8:])
+    else:
+        raise ValueError('Bad address format?')
 
     return zone, name
 
@@ -118,7 +123,7 @@ def dns_zone_exists(name):
 
 def add_zone(name, zonemgr=None, dns_backup=None, nsaddr=None, update_policy=None):
     if not update_policy:
-        update_policy = "grant %s krb5-self * A;" % api.env.realm
+        update_policy = "grant %(realm)s krb5-self * A; grant %(realm)s krb5-self * AAAA;" % dict(realm=api.env.realm)
 
     try:
         api.Command.dnszone_add(unicode(name),
@@ -160,6 +165,13 @@ def add_rr(zone, name, type, rdata, dns_backup=None, **kwargs):
     if dns_backup:
         dns_backup.add(zone, type, name, rdata)
 
+def add_fwd_rr(zone, host, ip_address):
+    addr = netaddr.IPAddress(ip_address)
+    if addr.version == 4:
+        add_rr(zone, host, "A", ip_address)
+    elif addr.version == 6:
+        add_rr(zone, host, "AAAA", ip_address)
+
 def add_ptr_rr(ip_address, fqdn, dns_backup=None):
     zone, name = get_reverse_zone(ip_address)
     add_rr(zone, name, "PTR", fqdn+".", dns_backup)
@@ -264,11 +276,7 @@ class BindInstance(service.Service):
         else:
             self.zonemgr = 'root.%s.%s' % (self.host, self.domain)
 
-        tmp = ip_address.split(".")
-        tmp.reverse()
-
-        self.reverse_host = tmp.pop(0)
-        self.reverse_subnet = ".".join(tmp)
+        self.reverse_subnet, self.reverse_host = get_reverse_zone(ip_address)
 
         self.__setup_sub_dict()
 
@@ -357,7 +365,6 @@ class BindInstance(service.Service):
     def __add_self(self):
         zone = self.domain
         resource_records = (
-            (self.host, "A", self.ip_address),
             ("_ldap._tcp", "SRV", "0 100 389 %s" % self.host),
             ("_kerberos", "TXT", self.realm),
             ("_kerberos._tcp", "SRV", "0 100 88 %s" % self.host),
@@ -376,6 +383,8 @@ class BindInstance(service.Service):
         if self.ntp:
             add_rr(zone, "_ntp._udp", "SRV", "0 100 123 %s" % self.host)
 
+        # Add forward and reverse records to self
+        add_fwd_rr(zone, self.host, self.ip_address)
         if dns_zone_exists(get_reverse_zone(self.ip_address)[0]):
             add_ptr_rr(self.ip_address, self.fqdn)
 
diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py
index 05d397e..314c26c 100644
--- a/ipaserver/install/installutils.py
+++ b/ipaserver/install/installutils.py
@@ -133,12 +133,12 @@ def verify_fqdn(host_name,no_host_dns=False):
 
     # Verify that it is a DNS A or AAAA record
     rs = dnsclient.query(host_name+".", dnsclient.DNS_C_IN, dnsclient.DNS_T_A)
-    if len(rs) > 0:
+    if len([ rec for rec in rs if rec.dns_type is not dnsclient.DNS_T_SOA ]) > 0:
         verify_dns_records(host_name, rs, resaddr, 'ipv4')
         return
 
     rs = dnsclient.query(host_name+".", dnsclient.DNS_C_IN, dnsclient.DNS_T_AAAA)
-    if len(rs) > 0:
+    if len([ rec for rec in rs if rec.dns_type is not dnsclient.DNS_T_SOA ]) > 0:
         verify_dns_records(host_name, rs, resaddr, 'ipv6')
         return
     else:
-- 
1.7.3.5

Attachment: jhrozek-freeipa-048-ipv6.patch.sig
Description: PGP signature

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

Reply via email to