It seems I sent two patches with number 189. Sending a patch with a correct number.
Martin On Tue, 2012-01-10 at 12:40 +0100, Martin Kosek wrote: > Depends on my patch 188 > --- > A server may have 2 or more NICs and its hostname may thus resolve > to 2 and more forward addresses. IP address checks in install > scripts does not expect this setup and may fail or crash. > > This script adds a support for multiple forward addresses for > a hostname. The install scripts do not crash now. When one IP > address is needed, user is asked to choose from all detected > server IP addresses. > > https://fedorahosted.org/freeipa/ticket/2154
>From bc6d8c3407c01afa688012cf2fdffb13947228b3 Mon Sep 17 00:00:00 2001 From: Martin Kosek <[email protected]> Date: Tue, 10 Jan 2012 12:18:15 +0100 Subject: [PATCH] Fix ipa-server-install for dual NICs A server may have 2 or more NICs and its hostname may thus resolve to 2 and more forward addresses. IP address checks in install scripts does not expect this setup and may fail or crash. This script adds a support for multiple forward addresses for a hostname. The install scripts do not crash now. When one IP address is needed, user is asked to choose from all detected server IP addresses. https://fedorahosted.org/freeipa/ticket/2154 --- install/tools/ipa-adtrust-install | 2 +- install/tools/ipa-dns-install | 13 +++++- install/tools/ipa-replica-conncheck | 2 +- install/tools/ipa-replica-install | 27 ++++-------- ipapython/dnsclient.py | 78 +++++++++++++++++++--------------- ipaserver/install/bindinstance.py | 16 ++++++- ipaserver/install/installutils.py | 58 ++++++++++++++++++-------- 7 files changed, 122 insertions(+), 74 deletions(-) diff --git a/install/tools/ipa-adtrust-install b/install/tools/ipa-adtrust-install index 248ea35eaa86dd59ebbc871b86df780cfd71ccf6..1c5940db87ac22b82c0057eb2a84a25691189432 100755 --- a/install/tools/ipa-adtrust-install +++ b/install/tools/ipa-adtrust-install @@ -136,7 +136,7 @@ def main(): ip = ipautil.CheckedIPAddress(options.ip_address, match_local=True) else: hostaddr = resolve_host(api.env.host) - ip = hostaddr and ipautil.CheckedIPAddress(hostaddr, match_local=True) + ip = hostaddr and ipautil.CheckedIPAddress(hostaddr[0], match_local=True) except Exception, e: print "Error: Invalid IP Address %s: %s" % (ip, e) ip = None diff --git a/install/tools/ipa-dns-install b/install/tools/ipa-dns-install index 5c02c20c05dd74cf8a4134e510114a54b5259031..2c0fa51d786e4882a18e25a02a53e812b47538c6 100755 --- a/install/tools/ipa-dns-install +++ b/install/tools/ipa-dns-install @@ -147,7 +147,18 @@ def main(): else: hostaddr = resolve_host(api.env.host) try: - ip = hostaddr and ipautil.CheckedIPAddress(hostaddr, match_local=True) + if len(hostaddr) > 1: + print >> sys.stderr, "The server hostname resolves to more than one address:" + for addr in hostaddr: + print >> sys.stderr, " %s" % addr + + if options.unattended: + print >> sys.stderr, "Please use --ip-address option to specify the address" + sys.exit(1) + else: + ip = read_ip_address(api.env.host, fstore) + else: + ip = hostaddr and ipautil.CheckedIPAddress(hostaddr[0], match_local=True) except Exception, e: print "Error: Invalid IP Address %s: %s" % (ip, e) ip = None diff --git a/install/tools/ipa-replica-conncheck b/install/tools/ipa-replica-conncheck index 882d77d302bef0abd6a9d06d4cd783fcbafeefe0..2622130e7c6f6ceabe6ff8a17e89412089897c5f 100755 --- a/install/tools/ipa-replica-conncheck +++ b/install/tools/ipa-replica-conncheck @@ -237,7 +237,7 @@ class PortResponder(threading.Thread): def port_check(host, port_list): ip = installutils.resolve_host(host) - if ip is None: + if not ip: raise RuntimeError("Port check failed! Unable to resolve host name '%s'" % host) failed_ports = [] diff --git a/install/tools/ipa-replica-install b/install/tools/ipa-replica-install index 34c787b1919b89bd1e9ad4aaec1ace7daaebc36e..c1474ecbffc6ac5ccc22b91098dbdb1aa4613f0f 100755 --- a/install/tools/ipa-replica-install +++ b/install/tools/ipa-replica-install @@ -200,27 +200,22 @@ def install_bind(config, options): else: forwarders = () bind = bindinstance.BindInstance(dm_password=config.dirman_password) - ip_address = resolve_host(config.host_name) - if not ip_address: - sys.exit("Unable to resolve IP address for host name") - ip = ipautil.CheckedIPAddress(ip_address, match_local=True) - ip_address = str(ip) if options.reverse_zone: - if not bindinstance.verify_reverse_zone(options.reverse_zone, ip): + if not bindinstance.verify_reverse_zone(options.reverse_zone, config.ip): sys.exit(1) reverse_zone = bindinstance.normalize_zone(options.reverse_zone) else: - reverse_zone = bindinstance.find_reverse_zone(ip) + reverse_zone = bindinstance.find_reverse_zone(config.ip) if reverse_zone is None and not options.no_reverse: - reverse_zone = bindinstance.get_reverse_zone_default(ip) + reverse_zone = bindinstance.get_reverse_zone_default(config.ip) if not options.unattended and bindinstance.create_reverse(): - reverse_zone = bindinstance.read_reverse_zone(reverse_zone, ip) + reverse_zone = bindinstance.read_reverse_zone(reverse_zone, config.ip) if reverse_zone is not None: print "Using reverse zone %s" % reverse_zone - bind.setup(config.host_name, ip_address, config.realm_name, + bind.setup(config.host_name, config.ip_address, config.realm_name, config.domain_name, forwarders, options.conf_ntp, reverse_zone) bind.create_instance() @@ -240,14 +235,9 @@ def install_dns_records(config, options): bind_pw=config.dirman_password, tls_cacertfile=CACERT) bind = bindinstance.BindInstance(dm_password=config.dirman_password) - ip_address = resolve_host(config.host_name) - if not ip_address: - sys.exit("Unable to resolve IP address for host name") - ip = ipautil.CheckedIPAddress(ip_address, match_local=True) - ip_address = str(ip) - reverse_zone = bindinstance.find_reverse_zone(ip) + reverse_zone = bindinstance.find_reverse_zone(config.ip) - bind.add_master_dns_records(config.host_name, ip_address, + bind.add_master_dns_records(config.host_name, config.ip_address, config.realm_name, config.domain_name, reverse_zone, options.conf_ntp) @@ -341,7 +331,8 @@ def main(): replica_conn_check(config.master_host_name, config.host_name, config.realm_name, options.setup_ca, options.admin_password) # check replica host IP resolution - ip = installutils.get_server_ip_address(config.host_name, fstore, True, options) + config.ip = installutils.get_server_ip_address(config.host_name, fstore, True, options) + config.ip_address = str(config.ip) # Create the management framework config file # Note: We must do this before bootstraping and finalizing ipalib.api diff --git a/ipapython/dnsclient.py b/ipapython/dnsclient.py index 9a59d9b99ef0e6c6b5754cd4f18bf9162d39f0b3..3f08866a6403c3f2616ec954ef5c70aa4c849a92 100644 --- a/ipapython/dnsclient.py +++ b/ipapython/dnsclient.py @@ -40,6 +40,11 @@ DNS_T_AAAA = 28 DNS_T_SRV = 33 DNS_T_ANY = 255 +DNS_S_QUERY = 1 +DNS_S_ANSWER = 2 +DNS_S_AUTHORITY = 3 +DNS_S_ADDITIONAL = 4 + DEBUG_DNSCLIENT = False class DNSQueryHeader: @@ -105,6 +110,7 @@ class DNSResult: self.dns_ttl = 0 self.dns_rlength = 0 self.rdata = None + self.section = None def unpack(self, data): (self.dns_type, self.dns_class, self.dns_ttl, @@ -398,47 +404,51 @@ def dnsParseResults(results): print "Queried for '%s', class = %d, type = %d." % (label, qq.dns_class, qq.dns_type) - for i in xrange(header.dns_ancount + header.dns_nscount + header.dns_arcount): - (rest, label) = dnsParseLabel(rest, results) - if label is None: - return [] + for (rec_count, section_id) in ((header.dns_ancount, DNS_S_ANSWER), + (header.dns_nscount, DNS_S_AUTHORITY), + (header.dns_arcount, DNS_S_ADDITIONAL)): + for i in xrange(rec_count): + (rest, label) = dnsParseLabel(rest, results) + if label is None: + return [] - rr = DNSResult() + rr = DNSResult() - rr.dns_name = label + rr.dns_name = label + rr.section = section_id - if len(rest) < rr.size(): - return [] + if len(rest) < rr.size(): + return [] - rr.unpack(rest) - - rest = rest[rr.size():] + rr.unpack(rest) - if DEBUG_DNSCLIENT: - print "Answer %d for '%s', class = %d, type = %d, ttl = %d." % (i, - rr.dns_name, rr.dns_class, rr.dns_type, - rr.dns_ttl) + rest = rest[rr.size():] - if len(rest) < rr.dns_rlength: if DEBUG_DNSCLIENT: - print "Answer too short." - return [] - - fmap = { DNS_T_A: dnsParseA, DNS_T_NS: dnsParseNS, - DNS_T_CNAME: dnsParseCNAME, DNS_T_SOA: dnsParseSOA, - DNS_T_NULL: dnsParseNULL, DNS_T_WKS: dnsParseWKS, - DNS_T_PTR: dnsParsePTR, DNS_T_HINFO: dnsParseHINFO, - DNS_T_MX: dnsParseMX, DNS_T_TXT: dnsParseTXT, - DNS_T_AAAA : dnsParseAAAA, DNS_T_SRV: dnsParseSRV} - - if not rr.dns_type in fmap: - if DEBUG_DNSCLIENT: - print "Don't know how to parse RR type %d!" % rr.dns_type - else: - rr.rdata = fmap[rr.dns_type](rest[:rr.dns_rlength], results) - - rest = rest[rr.dns_rlength:] - rrlist += [rr] + print "Answer %d for '%s', class = %d, type = %d, ttl = %d." % (i, + rr.dns_name, rr.dns_class, rr.dns_type, + rr.dns_ttl) + + if len(rest) < rr.dns_rlength: + if DEBUG_DNSCLIENT: + print "Answer too short." + return [] + + fmap = { DNS_T_A: dnsParseA, DNS_T_NS: dnsParseNS, + DNS_T_CNAME: dnsParseCNAME, DNS_T_SOA: dnsParseSOA, + DNS_T_NULL: dnsParseNULL, DNS_T_WKS: dnsParseWKS, + DNS_T_PTR: dnsParsePTR, DNS_T_HINFO: dnsParseHINFO, + DNS_T_MX: dnsParseMX, DNS_T_TXT: dnsParseTXT, + DNS_T_AAAA : dnsParseAAAA, DNS_T_SRV: dnsParseSRV} + + if not rr.dns_type in fmap: + if DEBUG_DNSCLIENT: + print "Don't know how to parse RR type %d!" % rr.dns_type + else: + rr.rdata = fmap[rr.dns_type](rest[:rr.dns_rlength], results) + + rest = rest[rr.dns_rlength:] + rrlist += [rr] return rrlist diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py index c7e382822c47586069f2189a37a33677330c4dda..6e6c941114831a4fb466610e8c0b714a07955f6c 100644 --- a/ipaserver/install/bindinstance.py +++ b/ipaserver/install/bindinstance.py @@ -197,7 +197,13 @@ def add_zone(name, zonemgr=None, dns_backup=None, ns_hostname=None, ns_ip_addres 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) + addresses = resolve_host(ns_main) + + if len(addresses) > 0: + # use the first address + ns_ip_address = addresses[0] + else: + ns_ip_address = None else: ns_main = ns_hostname ns_replicas = [] @@ -230,7 +236,13 @@ def add_reverse_zone(zone, ns_hostname=None, ns_ip_address=None, 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) + addresses = resolve_host(ns_main) + + if len(addresses) > 0: + # use the first address + ns_ip_address = addresses[0] + else: + ns_ip_address = None else: ns_main = ns_hostname ns_replicas = [] diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py index e2cabf69b6d90c20daf8848d69a062b301b2204e..6a9f8dbb500a8ab2a6cf36d8e9b81a1acf777761 100644 --- a/ipaserver/install/installutils.py +++ b/ipaserver/install/installutils.py @@ -90,27 +90,35 @@ def verify_dns_records(host_name, responses, resaddr, family): if family not in familykw.keys(): raise RuntimeError("Unknown faimily %s\n" % family) - rec = None + rec_list = [] for rsn in responses: - if rsn.dns_type == familykw[family]['dns_type']: - rec = rsn - break + if rsn.section == dnsclient.DNS_S_ANSWER and \ + rsn.dns_type == familykw[family]['dns_type']: + rec_list.append(rsn) - if rec == None: + if not rec_list: 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)) + familykw[family]['address'] = [socket.inet_ntop(socket.AF_INET, + struct.pack('!L',rec.rdata.address)) \ + for rec in rec_list] else: - familykw[family]['address'] = socket.inet_ntop(socket.AF_INET6, - struct.pack('!16B', *rec.rdata.address)) + familykw[family]['address'] = [socket.inet_ntop(socket.AF_INET6, + struct.pack('!16B', *rec.rdata.address)) \ + for rec in rec_list] # 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)) + dns_addrs = [netaddr.IPAddress(addr) for addr in familykw[family]['address']] + dns_addr = None + for addr in dns_addrs: + if addr.format() == resaddr: + dns_addr = addr + break + + if dns_addr is None: + raise RuntimeError("Host address %s does not match any address in DNS lookup." % resaddr) rs = dnsclient.query(dns_addr.reverse_dns, dnsclient.DNS_C_IN, dnsclient.DNS_T_PTR) if len(rs) == 0: @@ -498,14 +506,19 @@ def resolve_host(host_name): try: addrinfos = socket.getaddrinfo(host_name, None, socket.AF_UNSPEC, socket.SOCK_STREAM) + + ip_list = [] + for ai in addrinfos: ip = ai[4][0] if ip == "127.0.0.1" or ip == "::1": raise HostnameLocalhost("The hostname resolves to the localhost address") - return addrinfos[0][4][0] - except: - return None + ip_list.append(ip) + + return ip_list + except socket.error: + return [] def get_host_name(no_host_dns): """ @@ -534,8 +547,19 @@ def get_server_ip_address(host_name, fstore, unattended, options): sys.exit(1) ip_add_to_hosts = False - if hostaddr is not None: - ip = ipautil.CheckedIPAddress(hostaddr, match_local=True) + + if len(hostaddr) > 1: + print >> sys.stderr, "The server hostname resolves to more than one address:" + for addr in hostaddr: + print >> sys.stderr, " %s" % addr + + if unattended: + print >> sys.stderr, "Please use --ip-address option to specify the address" + sys.exit(1) + else: + ip = read_ip_address(host_name, fstore) + elif len(hostaddr) == 1: + ip = ipautil.CheckedIPAddress(hostaddr[0], match_local=True) else: # hostname is not resolvable ip = options.ip_address -- 1.7.7.5
_______________________________________________ Freeipa-devel mailing list [email protected] https://www.redhat.com/mailman/listinfo/freeipa-devel
