summaryrefslogtreecommitdiff
path: root/src/providers
diff options
context:
space:
mode:
authorJakub Hrozek <jhrozek@redhat.com>2013-04-09 17:40:40 +0200
committerJakub Hrozek <jhrozek@redhat.com>2013-05-03 20:25:46 +0200
commit5a4239490c7fb7d732180a9d40f27f0247c56631 (patch)
tree5d118934b4a922a1c549f1cc96b31c09ee60be64 /src/providers
parent04868f1573f4b26ef34610b6d7069172f93bd8ab (diff)
downloadsssd-5a4239490c7fb7d732180a9d40f27f0247c56631.tar.gz
sssd-5a4239490c7fb7d732180a9d40f27f0247c56631.tar.bz2
sssd-5a4239490c7fb7d732180a9d40f27f0247c56631.zip
dyndns: new option dyndns_refresh_interval
This new options adds the possibility of updating the DNS entries periodically regardless if they have changed or not. This feature will be useful mainly in AD environments where the Windows clients periodically update their DNS records.
Diffstat (limited to 'src/providers')
-rw-r--r--src/providers/dp_dyndns.c53
-rw-r--r--src/providers/dp_dyndns.h17
-rw-r--r--src/providers/ipa/ipa_common.c4
-rw-r--r--src/providers/ipa/ipa_dyndns.c107
-rw-r--r--src/providers/ipa/ipa_dyndns.h3
-rw-r--r--src/providers/ipa/ipa_opts.h1
6 files changed, 180 insertions, 5 deletions
diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
index 81228d5c..337817fc 100644
--- a/src/providers/dp_dyndns.c
+++ b/src/providers/dp_dyndns.c
@@ -879,6 +879,45 @@ be_nsupdate_recv(struct tevent_req *req, int *child_status)
return EOK;
}
+static void be_nsupdate_timer(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *pvt)
+{
+ struct be_nsupdate_ctx *ctx = talloc_get_type(pvt, struct be_nsupdate_ctx);
+
+ talloc_zfree(ctx->refresh_timer);
+ ctx->timer_callback(ctx->timer_pvt);
+
+ /* timer_callback is responsible for calling be_nsupdate_timer_schedule
+ * again */
+}
+
+void be_nsupdate_timer_schedule(struct tevent_context *ev,
+ struct be_nsupdate_ctx *ctx)
+{
+ int refresh;
+ struct timeval tv;
+
+ if (ctx->refresh_timer) {
+ DEBUG(SSSDBG_FUNC_DATA, ("Timer already scheduled\n"));
+ return;
+ }
+
+ refresh = dp_opt_get_int(ctx->opts, DP_OPT_DYNDNS_REFRESH_INTERVAL);
+ if (refresh == 0) return;
+ DEBUG(SSSDBG_FUNC_DATA, ("Scheduling timer in %d seconds\n", refresh));
+
+ tv = tevent_timeval_current_ofs(refresh, 0);
+ ctx->refresh_timer = tevent_add_timer(ev, ctx, tv,
+ be_nsupdate_timer, ctx);
+
+ if (!ctx->refresh_timer) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ ("Failed to add dyndns refresh timer event\n"));
+ }
+}
+
errno_t
be_nsupdate_check(void)
{
@@ -906,6 +945,7 @@ be_nsupdate_check(void)
static struct dp_option default_dyndns_opts[] = {
{ "dyndns_update", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
+ { "dyndns_refresh_interval", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER },
{ "dyndns_iface", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "dyndns_ttl", DP_OPT_NUMBER, { .number = 1200 }, NULL_NUMBER },
@@ -914,13 +954,16 @@ static struct dp_option default_dyndns_opts[] = {
errno_t
be_nsupdate_init(TALLOC_CTX *mem_ctx, struct be_ctx *be_ctx,
- struct dp_option *defopts, struct be_nsupdate_ctx **_ctx)
+ struct dp_option *defopts,
+ nsupdate_timer_fn_t timer_callback,
+ void *timer_pvt,
+ struct be_nsupdate_ctx **_ctx)
{
errno_t ret;
struct dp_option *src_opts;
struct be_nsupdate_ctx *ctx;
- ctx = talloc(mem_ctx, struct be_nsupdate_ctx);
+ ctx = talloc_zero(mem_ctx, struct be_nsupdate_ctx);
if (ctx == NULL) return ENOMEM;
src_opts = defopts ? defopts : default_dyndns_opts;
@@ -932,6 +975,10 @@ be_nsupdate_init(TALLOC_CTX *mem_ctx, struct be_ctx *be_ctx,
return ret;
}
+ ctx->timer_callback = timer_callback;
+ ctx->timer_pvt = timer_pvt;
+ be_nsupdate_timer_schedule(be_ctx->ev, ctx);
+
*_ctx = ctx;
- return EOK;
+ return ERR_OK;
}
diff --git a/src/providers/dp_dyndns.h b/src/providers/dp_dyndns.h
index 95403a3a..e49ab8f0 100644
--- a/src/providers/dp_dyndns.h
+++ b/src/providers/dp_dyndns.h
@@ -29,12 +29,21 @@
/* dynamic dns helpers */
struct sss_iface_addr;
+typedef void (*nsupdate_timer_fn_t)(void *pvt);
+
struct be_nsupdate_ctx {
struct dp_option *opts;
+
+ time_t last_refresh;
+ bool timer_in_progress;
+ struct tevent_timer *refresh_timer;
+ nsupdate_timer_fn_t timer_callback;
+ void *timer_pvt;
};
enum dp_dyndns_opts {
DP_OPT_DYNDNS_UPDATE,
+ DP_OPT_DYNDNS_REFRESH_INTERVAL,
DP_OPT_DYNDNS_IFACE,
DP_OPT_DYNDNS_TTL,
@@ -48,7 +57,13 @@ errno_t be_nsupdate_check(void);
errno_t
be_nsupdate_init(TALLOC_CTX *mem_ctx, struct be_ctx *be_ctx,
- struct dp_option *defopts, struct be_nsupdate_ctx **ctx);
+ struct dp_option *defopts,
+ nsupdate_timer_fn_t timer_callback,
+ void *timer_pvt,
+ struct be_nsupdate_ctx **_ctx);
+
+void be_nsupdate_timer_schedule(struct tevent_context *ev,
+ struct be_nsupdate_ctx *ctx);
errno_t
sss_iface_addr_list_get(TALLOC_CTX *mem_ctx, const char *ifname,
diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
index 51750b2a..baece274 100644
--- a/src/providers/ipa/ipa_common.c
+++ b/src/providers/ipa/ipa_common.c
@@ -28,6 +28,7 @@
#include "db/sysdb_selinux.h"
#include "providers/ipa/ipa_common.h"
+#include "providers/ipa/ipa_dyndns.h"
#include "providers/ldap/sdap_async_private.h"
#include "providers/dp_dyndns.h"
#include "util/sss_krb5.h"
@@ -1018,7 +1019,8 @@ errno_t ipa_get_dyndns_options(struct be_ctx *be_ctx,
bool update;
int ttl;
- ret = be_nsupdate_init(ctx, be_ctx, ipa_dyndns_opts, &ctx->dyndns_ctx);
+ ret = be_nsupdate_init(ctx, be_ctx, ipa_dyndns_opts, ipa_dyndns_timer,
+ ctx, &ctx->dyndns_ctx);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
("Cannot initialize IPA dyndns opts [%d]: %s\n",
diff --git a/src/providers/ipa/ipa_dyndns.c b/src/providers/ipa/ipa_dyndns.c
index 8023b533..52b8051b 100644
--- a/src/providers/ipa/ipa_dyndns.c
+++ b/src/providers/ipa/ipa_dyndns.c
@@ -55,6 +55,98 @@ errno_t ipa_dyndns_init(struct be_ctx *be_ctx,
return EOK;
}
+struct ipa_dyndns_timer_ctx {
+ struct sdap_id_op *sdap_op;
+ struct tevent_context *ev;
+
+ struct ipa_options *ctx;
+};
+
+static void ipa_dyndns_timer_connected(struct tevent_req *req);
+
+void ipa_dyndns_timer(void *pvt)
+{
+ struct ipa_options *ctx = talloc_get_type(pvt, struct ipa_options);
+ struct sdap_id_ctx *sdap_ctx = ctx->id_ctx->sdap_id_ctx;
+ struct tevent_req *req;
+ struct ipa_dyndns_timer_ctx *timer_ctx;
+ errno_t ret;
+
+ timer_ctx = talloc_zero(ctx, struct ipa_dyndns_timer_ctx);
+ if (timer_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Out of memory\n"));
+ /* Not much we can do */
+ return;
+ }
+ timer_ctx->ev = sdap_ctx->be->ev;
+ timer_ctx->ctx = ctx;
+
+ /* In order to prevent the connection triggering an
+ * online callback which would in turn trigger a concurrent DNS
+ * update
+ */
+ ctx->dyndns_ctx->timer_in_progress = true;
+
+ /* Make sure to have a valid LDAP connection */
+ timer_ctx->sdap_op = sdap_id_op_create(timer_ctx, sdap_ctx->conn_cache);
+ if (timer_ctx->sdap_op == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, ("sdap_id_op_create failed\n"));
+ goto fail;
+ }
+
+ req = sdap_id_op_connect_send(timer_ctx->sdap_op, timer_ctx, &ret);
+ if (req == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, ("sdap_id_op_connect_send failed: [%d](%s)\n",
+ ret, sss_strerror(ret)));
+ goto fail;
+ }
+ tevent_req_set_callback(req, ipa_dyndns_timer_connected, timer_ctx);
+ return;
+
+fail:
+ ctx->dyndns_ctx->timer_in_progress = false;
+ be_nsupdate_timer_schedule(timer_ctx->ev, ctx->dyndns_ctx);
+ talloc_free(timer_ctx);
+}
+
+static void ipa_dyndns_timer_connected(struct tevent_req *req)
+{
+ errno_t ret;
+ int dp_error;
+ struct ipa_dyndns_timer_ctx *timer_ctx = tevent_req_callback_data(req,
+ struct ipa_dyndns_timer_ctx);
+ struct tevent_context *ev;
+ struct ipa_options *ctx;
+
+ ctx = timer_ctx->ctx;
+ ev = timer_ctx->ev;
+ ctx->dyndns_ctx->timer_in_progress = false;
+
+ ret = sdap_id_op_connect_recv(req, &dp_error);
+ talloc_zfree(req);
+ talloc_free(timer_ctx);
+ if (ret != EOK) {
+ if (dp_error == DP_ERR_OFFLINE) {
+ DEBUG(SSSDBG_MINOR_FAILURE, ("No IPA server is available, "
+ "dynamic DNS update is skipped in offline mode.\n"));
+ /* Another timer will be scheduled when provider goes online
+ * and ipa_dyndns_update() is called */
+ } else {
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("Failed to connect to LDAP server: [%d](%s)\n",
+ ret, sss_strerror(ret)));
+
+ /* Just schedule another dyndns retry */
+ be_nsupdate_timer_schedule(ev, ctx->dyndns_ctx);
+ }
+ return;
+ }
+
+ /* all OK just call ipa_dyndns_update and schedule another refresh */
+ be_nsupdate_timer_schedule(ev, ctx->dyndns_ctx);
+ return ipa_dyndns_update(ctx);
+}
+
static struct tevent_req *ipa_dyndns_update_send(struct ipa_options *ctx);
static errno_t ipa_dyndns_update_recv(struct tevent_req *req);
@@ -63,6 +155,11 @@ static void ipa_dyndns_nsupdate_done(struct tevent_req *subreq);
void ipa_dyndns_update(void *pvt)
{
struct ipa_options *ctx = talloc_get_type(pvt, struct ipa_options);
+ struct sdap_id_ctx *sdap_ctx = ctx->id_ctx->sdap_id_ctx;
+
+ /* Schedule timer after provider went offline */
+ be_nsupdate_timer_schedule(sdap_ctx->be->ev, ctx->dyndns_ctx);
+
struct tevent_req *req = ipa_dyndns_update_send(ctx);
if (req == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Could not update DNS\n"));
@@ -109,6 +206,16 @@ ipa_dyndns_update_send(struct ipa_options *ctx)
}
state->ipa_ctx = ctx;
+ if (ctx->dyndns_ctx->last_refresh + 60 > time(NULL) ||
+ ctx->dyndns_ctx->timer_in_progress) {
+ DEBUG(SSSDBG_FUNC_DATA, ("Last periodic update ran recently or timer"
+ "in progress, not scheduling another update\n"));
+ tevent_req_done(req);
+ tevent_req_post(req, sdap_ctx->be->ev);
+ return req;
+ }
+ state->ipa_ctx->dyndns_ctx->last_refresh = time(NULL);
+
dns_zone = dp_opt_get_string(ctx->basic, IPA_DOMAIN);
if (!dns_zone) {
ret = EIO;
diff --git a/src/providers/ipa/ipa_dyndns.h b/src/providers/ipa/ipa_dyndns.h
index d86c6634..ced3f097 100644
--- a/src/providers/ipa/ipa_dyndns.h
+++ b/src/providers/ipa/ipa_dyndns.h
@@ -25,6 +25,9 @@
#ifndef IPA_DYNDNS_H_
#define IPA_DYNDNS_H_
+void ipa_dyndns_update(void *pvt);
+void ipa_dyndns_timer(void *pvt);
+
errno_t ipa_dyndns_init(struct be_ctx *be_ctx,
struct ipa_options *ctx);
diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
index 392fcd86..57911082 100644
--- a/src/providers/ipa/ipa_opts.h
+++ b/src/providers/ipa/ipa_opts.h
@@ -53,6 +53,7 @@ struct dp_option ipa_basic_opts[] = {
struct dp_option ipa_dyndns_opts[] = {
{ "dyndns_update", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
+ { "dyndns_refresh_interval", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER },
{ "dyndns_iface", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "dyndns_ttl", DP_OPT_NUMBER, { .number = 1200 }, NULL_NUMBER },
DP_OPTION_TERMINATOR