[SSSD] [PATCH] Fixes for dynamic DNS update

Sumit Bose sbose at redhat.com
Mon Feb 28 11:38:12 UTC 2011


On Fri, Feb 25, 2011 at 08:05:08AM -0500, Simo Sorce wrote:
> On Fri, 25 Feb 2011 13:06:22 +0100
> Sumit Bose <sbose at redhat.com> wrote:
> 
> > Hi,
> > 
> > this patch should fix trac ticket #810 and fixes pro-actively a
> > potential issue with the realm.
> > 
> > bye,
> > Sumit
> 
> NACK,
> not all IPA server are necessarily also a DNS server.
> Specifying a server may make the code try to reach a server that
> doesn't host a DNS instance.
> 
> I see 2 possibilities here.
> Try once with the server explicitly and if it fails fallback to let
> nsupdate find the server from the SOA record.
> Or always let nsupdate find the SOA record and try to fallback to
> explicit server if that fails.

Thank you for the review. I took the second possibility, because I think
it is the more general approach. There might be one drawback. Depending
on how the IPA DNS server sets the master name field in the SOA record
all dynamic updates might be send to a single server. If you prefer the
other possibility in this case I can easily modify the patch.

bye,
Sumit

> 
> Simo.
> 
> -- 
> Simo Sorce * Red Hat, Inc * New York
-------------- next part --------------
From 02d63be3c391e5e9b18e9a07abc1711adbf2edf9 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Fri, 25 Feb 2011 12:52:59 +0100
Subject: [PATCH] Fixes for dynamic DNS update

The current code assumed that only one server is given in the ipa_server
config option and fails if multiple servers were given. To fix this
nsupdate is first called without a server name assuming that nsupdate is
able to find the name of the master DNS server of the zone by reading
the SOA record. If this fails the IP address of the currently active
LDAP server is used and nsupdate is called again.

If there is no default realm given in /etc/krb5.conf nsupdate start
trying to find a realm based on the DNS domain which might lead to wrong
results. To be on the safe side the realm was added to the message send
to nsupdate.
---
 src/providers/ipa/ipa_dyndns.c |  103 +++++++++++++++++++++++++++++++++------
 1 files changed, 87 insertions(+), 16 deletions(-)

diff --git a/src/providers/ipa/ipa_dyndns.c b/src/providers/ipa/ipa_dyndns.c
index af94283..bee4bff 100644
--- a/src/providers/ipa/ipa_dyndns.c
+++ b/src/providers/ipa/ipa_dyndns.c
@@ -54,7 +54,7 @@ struct ipa_dyndns_ctx {
     struct sdap_id_op* sdap_op;
     char *hostname;
     struct ipa_ipaddress *addresses;
-    int child_status;
+    bool use_server_with_nsupdate;
 };
 
 
@@ -101,6 +101,7 @@ ipa_dyndns_update_send(struct ipa_options *ctx)
         return NULL;
     }
     state->ipa_ctx = ctx;
+    state->use_server_with_nsupdate = false;
 
     iface = dp_opt_get_string(ctx->basic, IPA_DYNDNS_IFACE);
 
@@ -301,10 +302,12 @@ struct ipa_nsupdate_ctx {
     struct ipa_dyndns_ctx *dyndns_ctx;
     int pipefd_to_child;
     struct tevent_timer *timeout_handler;
+    int child_status;
 };
 
 
-static int create_nsupdate_message(struct ipa_nsupdate_ctx *ctx);
+static int create_nsupdate_message(struct ipa_nsupdate_ctx *ctx,
+                                   bool use_server_with_nsupdate);
 
 static struct tevent_req *
 fork_nsupdate_send(struct ipa_nsupdate_ctx *ctx);
@@ -324,9 +327,10 @@ ipa_dyndns_gss_tsig_update_send(struct ipa_dyndns_ctx *ctx)
         return NULL;
     }
     state->dyndns_ctx = ctx;
+    state->child_status = 0;
 
     /* Format the message to pass to the nsupdate command */
-    ret = create_nsupdate_message(state);
+    ret = create_nsupdate_message(state, ctx->use_server_with_nsupdate);
     if (ret != EOK) {
         goto failed;
     }
@@ -347,20 +351,22 @@ failed:
 
 struct nsupdate_send_ctx {
     struct ipa_nsupdate_ctx *nsupdate_ctx;
+    int child_status;
 };
 
-static int create_nsupdate_message(struct ipa_nsupdate_ctx *ctx)
+static int create_nsupdate_message(struct ipa_nsupdate_ctx *ctx,
+                                   bool use_server_with_nsupdate)
 {
     int ret, i;
-    char *servername;
+    char *servername = NULL;
+    char *realm;
     char *zone;
     char ip_addr[INET6_ADDRSTRLEN];
     const char *ip;
     struct ipa_ipaddress *new_record;
 
-    servername = dp_opt_get_string(ctx->dyndns_ctx->ipa_ctx->basic,
-                                   IPA_SERVER);
-    if (!servername) {
+    realm = dp_opt_get_string(ctx->dyndns_ctx->ipa_ctx->basic, IPA_KRB5_REALM);
+    if (!realm) {
         return EIO;
     }
 
@@ -377,10 +383,31 @@ static int create_nsupdate_message(struct ipa_nsupdate_ctx *ctx)
         zone[i] = tolower(zone[i]);
     }
 
-    /* Add the server and zone headers */
-    ctx->update_msg = talloc_asprintf(ctx, "server %s\nzone %s.\n",
-                                           servername,
-                                           zone);
+    if (use_server_with_nsupdate) {
+        if (strncmp(ctx->dyndns_ctx->ipa_ctx->service->sdap->uri,
+                    "ldap://", 7) != 0) {
+            DEBUG(1, ("Unexpected format of LDAP URI.\n"));
+            return EIO;
+        }
+        servername = ctx->dyndns_ctx->ipa_ctx->service->sdap->uri + 7;
+        if (!servername) {
+            return EIO;
+        }
+
+        DEBUG(9, ("Creating update message for server [%s], realm [%s] "
+                  "and zone [%s].\n", servername, realm, zone));
+
+        /* Add the server, realm and zone headers */
+        ctx->update_msg = talloc_asprintf(ctx, "server %s\nrealm %s\nzone %s.\n",
+                                               servername, realm, zone);
+    } else {
+        DEBUG(9, ("Creating update message for realm [%s] and zone [%s].\n",
+                  realm, zone));
+
+        /* Add the realm and zone headers */
+        ctx->update_msg = talloc_asprintf(ctx, "realm %s\nzone %s.\n",
+                                               realm, zone);
+    }
     if (ctx->update_msg == NULL) {
         ret = ENOMEM;
         goto done;
@@ -478,6 +505,7 @@ fork_nsupdate_send(struct ipa_nsupdate_ctx *ctx)
         return NULL;
     }
     state->nsupdate_ctx = ctx;
+    state->child_status = 0;
 
     ret = pipe(pipefd_to_child);
     if (ret == -1) {
@@ -597,6 +625,10 @@ static void ipa_dyndns_child_handler(int child_status,
                                      void *pvt)
 {
     struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
+    struct nsupdate_send_ctx *state =
+            tevent_req_data(req, struct nsupdate_send_ctx);
+
+    state->child_status = child_status;
 
     if (WIFEXITED(child_status) && WEXITSTATUS(child_status) != 0) {
         DEBUG(1, ("Dynamic DNS child failed with status [%d]\n",
@@ -615,6 +647,18 @@ static void ipa_dyndns_child_handler(int child_status,
     tevent_req_done(req);
 }
 
+static int ipa_dyndns_child_recv(struct tevent_req *req, int *child_status)
+{
+    struct nsupdate_send_ctx *state =
+            tevent_req_data(req, struct nsupdate_send_ctx);
+
+    *child_status = state->child_status;
+
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    return EOK;
+}
+
 static int ipa_dyndns_generic_recv(struct tevent_req *req)
 {
     TEVENT_REQ_RETURN_ON_ERROR(req);
@@ -627,8 +671,10 @@ static void fork_nsupdate_done(struct tevent_req *subreq)
     int ret;
     struct tevent_req *req =
             tevent_req_callback_data(subreq, struct tevent_req);
+    struct ipa_nsupdate_ctx *state = tevent_req_data(req,
+                                                     struct ipa_nsupdate_ctx);
 
-    ret = ipa_dyndns_generic_recv(subreq);
+    ret = ipa_dyndns_child_recv(subreq, &state->child_status);
     talloc_zfree(subreq);
     if (ret != EOK) {
         tevent_req_error(req, ret);
@@ -638,21 +684,46 @@ static void fork_nsupdate_done(struct tevent_req *subreq)
     tevent_req_done(req);
 }
 
+static int fork_nsupdate_recv(struct tevent_req *req, int *child_status)
+{
+    struct ipa_nsupdate_ctx *state =
+            tevent_req_data(req, struct ipa_nsupdate_ctx);
+
+    *child_status = state->child_status;
+
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    return EOK;
+}
+
 static void ipa_dyndns_gss_tsig_update_done(struct tevent_req *subreq)
 {
     /* Check the return code from the sigchld handler
      * and return it to the parent request.
      */
     int ret;
+    int child_status;
 
     struct tevent_req *req =
             tevent_req_callback_data(subreq, struct tevent_req);
+    struct ipa_dyndns_ctx *state = tevent_req_data(req, struct ipa_dyndns_ctx);
 
-    ret = ipa_dyndns_generic_recv(subreq);
+    ret = fork_nsupdate_recv(subreq, &child_status);
     talloc_zfree(subreq);
     if (ret != EOK) {
-        tevent_req_error(req, ret);
-        return;
+        if (state->use_server_with_nsupdate == false &&
+            WIFEXITED(child_status) && WEXITSTATUS(child_status) != 0) {
+            DEBUG(9, ("nsupdate failed, retrying with server name.\n"));
+            state->use_server_with_nsupdate = true;
+            ret = ipa_dyndns_gss_tsig_update_step(req);
+            if (ret != EOK) {
+                tevent_req_error(req, ret);
+            }
+            return;
+        } else {
+            tevent_req_error(req, ret);
+            return;
+        }
     }
 
     tevent_req_done(req);
-- 
1.7.4



More information about the sssd-devel mailing list