On Thu, 17 Feb 2011 11:53:52 -0500
Simo Sorce <sso...@redhat.com> wrote:

> On Thu, 17 Feb 2011 11:34:30 -0500
> Simo Sorce <sso...@redhat.com> wrote:
> 
> > 
> > If DNS Updates are available then try to register the ip address as
> > determined by connecting to the ipa server.
> > 
> > This allows also the creation of the DNS A record if none was
> > available before, which means you can add clients without having to
> > pre-register them in the DNS.
> > 
> > Fixes #935
> > 
> > Simo.
> > 
> 
> Forgot to add rpm dependency on bind-utils for the client package.
> 
> New patch attached.

After discussing a bit dns updates with Rob and Stephen on IRC here it
is a third patch that adds a --enable-dns-updates option.

Dns updates are performed only if this options is enabled or no entry
exists in DNS at all for the host.

If the option is enabled sssd is also configured to keep updating the
DNS during the life of the machine so that IP changes (laptops, dhcp,
etc..) are recorded in DNS properly.

Simo.

-- 
Simo Sorce * Red Hat, Inc * New York
>From d51f06ccd9e1c6a9d051850dcdac06ba0361d05f Mon Sep 17 00:00:00 2001
From: Simo Sorce <sso...@redhat.com>
Date: Thu, 17 Feb 2011 08:30:36 -0500
Subject: [PATCH] Try to register DNS name through a DNS Update on install.

Fixes: https://fedorahosted.org/freeipa/ticket/935
---
 freeipa.spec.in                           |    1 +
 ipa-client/ipa-install/ipa-client-install |  111 +++++++++++++++++++++++++++++
 ipaserver/plugins/join.py                 |    2 +-
 3 files changed, 113 insertions(+), 1 deletions(-)

diff --git a/freeipa.spec.in b/freeipa.spec.in
index f301aa26a66eb305369f4a4fe72e5c311ba86606..4def47598ec6fce5a7ce5e1dd80c029c9e46478a 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 20c327d492c28e0fdf2f5fec98e2d3d5d651e9fc..c4b0458d448a8d2d8dca2bc56b6b5024f192a7ee 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 992c6868eab12087f8439f29ab1e3a01ece3106a..81c336b27ae4be6800b97e397238205e30d96534 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']
-- 
1.7.4

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

Reply via email to