diff options
-rw-r--r-- | freeipa.spec.in | 1 | ||||
-rwxr-xr-x | ipa-client/ipa-install/ipa-client-install | 111 | ||||
-rw-r--r-- | ipaserver/plugins/join.py | 2 |
3 files changed, 113 insertions, 1 deletions
diff --git a/freeipa.spec.in b/freeipa.spec.in index f301aa26a..4def47598 100644 --- a/freeipa.spec.in +++ b/freeipa.spec.in @@ -138,6 +138,7 @@ Requires: xmlrpc-c Requires: sssd >= 1.5.1 Requires: certmonger >= 0.26 Requires: nss-tools +Requires: bind-utils Obsoletes: ipa-client >= 1.0 diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install index dc496225d..4b9bd29c6 100755 --- a/ipa-client/ipa-install/ipa-client-install +++ b/ipa-client/ipa-install/ipa-client-install @@ -32,6 +32,8 @@ try: import ipaclient.ipachangeconf import ipaclient.ntpconf from ipapython.ipautil import run, user_input, CalledProcessError, file_exists + from ipapython import ipautil + from ipapython import dnsclient from ipapython import sysrestore from ipapython import version from ipapython import certmonger @@ -83,6 +85,8 @@ def parse_options(): default=False, help="uninstall an existing installation") parser.add_option("", "--hostname", dest="hostname", help="The hostname of this server (FQDN). By default of nodename from uname(2) is used.") + parser.add_option("", "--enable-dns-updates", dest="dns_updates", action="store_true", default=False, + help="Configures the machine to attempt dns updates when the ip address changes.") options, args = parser.parse_args() safe_opts = parser.get_safe_opts(options) @@ -496,6 +500,9 @@ def configure_sssd_conf(fstore, cli_domain, cli_server, options): domain.set_option('cache_credentials', True) + if options.dns_updates: + domain.set_option('ipa_dyndns_update', True) + domain.set_active(True) sssdconfig.save_domain(domain) @@ -503,6 +510,101 @@ def configure_sssd_conf(fstore, cli_domain, cli_server, options): return 0 +def resolve_ipaddress(server): + """ Connect to the server's ldap port in order to determine what ip + address this machine uses as "public" ip (relative to the server). + """ + + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP) + s.connect((server, 389)) + addr, port = s.getsockname() + s.close() + + return addr + +UPDATE_TEMPLATE_A = """ +zone $ZONE. +update delete $HOSTNAME. IN A +send +update add $HOSTNAME. $TTL IN A $IPADDRESS +send +""" + +UPDATE_TEMPLATE_AAAA = """ +zone $ZONE. +update delete $HOSTNAME. IN AAAA +send +update add $HOSTNAME. $TTL IN AAAA $IPADDRESS +send +""" + +UPDATE_FILE = "/etc/ipa/.dns_update.txt" +CCACHE_FILE = "/etc/ipa/.dns_ccache" + +def update_dns(server, hostname): + + ip = resolve_ipaddress(server) + + sub_dict = dict(HOSTNAME=hostname, + IPADDRESS=ip, + TTL=1200, + ZONE='.'.join(hostname.split('.')[1:]) + ) + + template = None + if len(ip.split('.')) == 4: + template = UPDATE_TEMPLATE_A + elif len(ip.split(':')) > 1: + template = UPDATE_TEMPLATE_AAAA + + if template is None: + print >>sys.stderr, "Failed to determine machine's ip address." + print >>sys.stderr, "Failed to update DNS A record." + return + + update_txt = ipautil.template_str(template, sub_dict) + update_fd = file(UPDATE_FILE, "w") + update_fd.write(update_txt) + update_fd.flush() + update_fd.close() + + try: + ipautil.run(['/usr/bin/kinit', '-k', '-t', '/etc/krb5.keytab'], + env={'KRB5CCNAME':CCACHE_FILE}) + except CalledProcessError, e: + print >>sys.stderr, "Failed to obtain host TGT." + + try: + ipautil.run(['/usr/bin/nsupdate', '-g', "/etc/ipa/.dns_update.txt"], + env={'KRB5CCNAME':CCACHE_FILE}) + print "DNS server record set to: %s -> %s" % (hostname, ip) + except CalledProcessError, e: + print >>sys.stderr, "Failed to update DNS A record. (%s)" % str(e) + + try: + os.remove(UPDATE_FILE) + os.remove(CCACHE_FILE) + except: + pass + +def client_dns(server, hostname, dns_updates=False): + + dns_ok = False + + # Check if the client has an A record registered in its name. + rs = dnsclient.query(hostname+".", dnsclient.DNS_C_IN, dnsclient.DNS_T_A) + if len([ rec for rec in rs if rec.dns_type is not dnsclient.DNS_T_SOA ]) > 0: + dns_ok = True + else: + rs = dnsclient.query(hostname+".", dnsclient.DNS_C_IN, dnsclient.DNS_T_AAAA) + if len([ rec for rec in rs if rec.dns_type is not dnsclient.DNS_T_SOA ]) > 0: + dns_ok = True + else: + print "Warning: Hostname (%s) not found in DNS" % hostname + + if dns_updates or not dns_ok: + update_dns(server, hostname) + def main(): safe_options, options = parse_options() logging_setup(options) @@ -740,6 +842,15 @@ def main(): configure_certmonger(fstore, subject_base, cli_realm, options) + #Try to update the DNS records, failure is not fatal + if not options.on_master: + if options.hostname: + hostname = options.hostname + else: + hostname = socket.gethostname() + + client_dns(cli_server, hostname, options.dns_updates) + if options.sssd: nscd_action = "stop" nscd_status = "off" diff --git a/ipaserver/plugins/join.py b/ipaserver/plugins/join.py index 992c6868e..81c336b27 100644 --- a/ipaserver/plugins/join.py +++ b/ipaserver/plugins/join.py @@ -110,7 +110,7 @@ class join(Command): attrs_list = api.Command['host_show'](**kw)['result'] dn = attrs_list['dn'] except errors.NotFound: - attrs_list = api.Command['host_add'](hostname)['result'] + attrs_list = api.Command['host_add'](hostname, force=True)['result'] dn = attrs_list['dn'] config = api.Command['config_show']()['result'] |