diff options
author | Jakub Hrozek <jhrozek@redhat.com> | 2010-12-01 17:22:56 +0100 |
---|---|---|
committer | Rob Crittenden <rcritten@redhat.com> | 2010-12-20 11:27:34 -0500 |
commit | ee4d2739f11465ba6a7d817f9b988da5bfe86e2c (patch) | |
tree | 2640194c2e0adb7a95471420250b9b9ce0eb702f /ipaserver | |
parent | b328d845deaa2f894a6842a9920f46ea341572f2 (diff) | |
download | freeipa-ee4d2739f11465ba6a7d817f9b988da5bfe86e2c.tar.gz freeipa-ee4d2739f11465ba6a7d817f9b988da5bfe86e2c.tar.xz freeipa-ee4d2739f11465ba6a7d817f9b988da5bfe86e2c.zip |
Make the IPA installer IPv6 friendly
Notable changes include:
* parse AAAA records in dnsclient
* also ask for AAAA records when verifying FQDN
* do not use functions that are not IPv6 aware - notably socket.gethostbyname()
The complete list of functions was taken from http://www.akkadia.org/drepper/userapi-ipv6.html
section "Interface Checklist"
Diffstat (limited to 'ipaserver')
-rw-r--r-- | ipaserver/install/installutils.py | 109 | ||||
-rw-r--r-- | ipaserver/install/krbinstance.py | 2 |
2 files changed, 68 insertions, 43 deletions
diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py index 7863f11a7..ff2e2bd31 100644 --- a/ipaserver/install/installutils.py +++ b/ipaserver/install/installutils.py @@ -27,6 +27,7 @@ import fileinput import sys import struct import fcntl +import netaddr from ipapython import ipautil from ipapython import dnsclient @@ -42,8 +43,65 @@ def get_fqdn(): fqdn = "" return fqdn -def verify_fqdn(host_name,no_host_dns=False): +def verify_dns_records(host_name, responses, resaddr, family): + familykw = { 'ipv4' : { + 'dns_type' : dnsclient.DNS_T_A, + 'socket_family' : socket.AF_INET, + }, + 'ipv6' : { + 'dns_type' : dnsclient.DNS_T_AAAA, + 'socket_family' : socket.AF_INET6, + }, + } + + family = family.lower() + if family not in familykw.keys(): + raise RuntimeError("Unknown faimily %s\n" % family) + + if len(responses) == 0: + raise IOError(errno.ENOENT, + "Warning: Hostname (%s) not found with NSS calls" % host_name) + + rec = None + for rsn in responses: + if rsn.dns_type == familykw[family]['dns_type']: + rec = rsn + break + + if rec == None: + raise IOError(errno.ENOENT, + "Warning: Hostname (%s) not found in DNS" % host_name) + + if family == 'ipv4': + familykw[family]['address'] = socket.inet_ntop(socket.AF_INET, + struct.pack('!L',rec.rdata.address)) + else: + familykw[family]['address'] = socket.inet_ntop(socket.AF_INET6, + struct.pack('!16B', *rec.rdata.address)) + + # Check that DNS address is the same is address returned via standard glibc calls + dns_addr = netaddr.IPAddress(familykw[family]['address']) + if dns_addr.format() != resaddr: + raise RuntimeError("The network address %s does not match the DNS lookup %s. Check /etc/hosts and ensure that %s is the IP address for %s" % (dns_addr.format(), resaddr, dns_addr.format(), host_name)) + + rs = dnsclient.query(dns_addr.reverse_dns, dnsclient.DNS_C_IN, dnsclient.DNS_T_PTR) + if len(rs) == 0: + raise RuntimeError("Cannot find Reverse Address for %s (%s)" % (host_name, addr)) + rev = None + for rsn in rs: + if rsn.dns_type == dnsclient.DNS_T_PTR: + rev = rsn + break + + if rev == None: + raise RuntimeError("Cannot find Reverse Address for %s (%s)" % (host_name, addr)) + + if rec.dns_name != rev.rdata.ptrdname: + raise RuntimeError("The DNS forward record %s does not match the reverse address %s" % (rec.dns_name, rev.rdata.ptrdname)) + + +def verify_fqdn(host_name,no_host_dns=False): if len(host_name.split(".")) < 2 or host_name == "localhost.localdomain": raise RuntimeError("Invalid hostname: " + host_name) @@ -59,7 +117,7 @@ def verify_fqdn(host_name,no_host_dns=False): if a[4][0] == '127.0.0.1' or a[4][0] == '::1': raise RuntimeError("The IPA Server hostname cannot resolve to localhost (%s). A routable IP address must be used. Check /etc/hosts to see if %s is an alias for %s" % (a[4][0], host_name, a[4][0])) try: - revaddr = a[4][0] + resaddr = a[4][0] revname = socket.gethostbyaddr(a[4][0])[0] except: raise RuntimeError("Unable to resolve the reverse ip address, check /etc/hosts or DNS name resolution") @@ -77,48 +135,15 @@ def verify_fqdn(host_name,no_host_dns=False): if rsn.dns_type == dnsclient.DNS_T_CNAME: raise RuntimeError("The IPA Server Hostname cannot be a CNAME, only A names are allowed.") - # Verify that it is a DNS A record + # 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: - print "Warning: Hostname (%s) not found in DNS" % host_name - return - - rec = None - for rsn in rs: - if rsn.dns_type == dnsclient.DNS_T_A: - rec = rsn - break - - if rec == None: - print "Warning: Hostname (%s) not found in DNS" % host_name - return - - # Compare the forward and reverse - forward = rec.dns_name - - addr = socket.inet_ntoa(struct.pack('<L',rec.rdata.address)) - ipaddr = socket.inet_ntoa(struct.pack('!L',rec.rdata.address)) - if revaddr != ipaddr: - raise RuntimeError("The network address %s does not match the reverse lookup %s. Check /etc/hosts and ensure that %s is the IP address for %s" % (ipaddr, revaddr, ipaddr, host_name)) - - addr = addr + ".in-addr.arpa." - rs = dnsclient.query(addr, dnsclient.DNS_C_IN, dnsclient.DNS_T_PTR) - if len(rs) == 0: - raise RuntimeError("Cannot find Reverse Address for %s (%s)" % (host_name, addr)) - - rev = None - for rsn in rs: - if rsn.dns_type == dnsclient.DNS_T_PTR: - rev = rsn - break - - if rev == None: - raise RuntimeError("Cannot find Reverse Address for %s (%s)" % (host_name, addr)) - - reverse = rev.rdata.ptrdname + try: + verify_dns_records(host_name, rs, resaddr, 'ipv4') + except IOError, e: + if e.errno == errno.ENOENT: # retry IPv6 + rs = dnsclient.query(host_name+".", dnsclient.DNS_C_IN, dnsclient.DNS_T_AAAA) + verify_dns_records(host_name, rs, resaddr, 'ipv6') - if forward != reverse: - raise RuntimeError("The DNS forward record %s does not match the reverse address %s" % (forward, reverse)) def verify_ip_address(ip): is_ok = True diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py index c1e5a3f0a..bffd7c1b9 100644 --- a/ipaserver/install/krbinstance.py +++ b/ipaserver/install/krbinstance.py @@ -135,7 +135,7 @@ class KrbInstance(service.Service): self.fqdn = host_name self.realm = realm_name.upper() self.host = host_name.split(".")[0] - self.ip = socket.gethostbyname(host_name) + self.ip = socket.getaddrinfo(host_name, None, socket.AF_UNSPEC, socket.SOCK_STREAM)[0][4][0] self.domain = domain_name self.suffix = util.realm_to_suffix(self.realm) self.kdc_password = ipautil.ipa_generate_password() |