sdap_dyndns.c revision 33df734b39538eeb870b118b7feea76f90bb004b
/*
SSSD
sdap_dyndns.c: LDAP specific dynamic DNS update
Authors:
Jakub Hrozek <jhrozek@redhat.com>
Copyright (C) 2013 Red Hat
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "resolv/async_resolv.h"
#include "providers/dp_backend.h"
#include "providers/dp_dyndns.h"
#include "providers/ldap/sdap_async_private.h"
#include "providers/ldap/sdap_id_op.h"
#include "providers/ldap/ldap_common.h"
static struct tevent_req *
struct tevent_context *ev,
struct sdap_id_ctx *sdap_ctx,
const char *iface);
static errno_t
struct sss_iface_addr **_addresses);
struct sdap_dyndns_update_state {
struct tevent_context *ev;
struct be_resolv_ctx *be_res;
const char *hostname;
const char *dns_zone;
const char *realm;
const char *servername;
int ttl;
struct sss_iface_addr *addresses;
struct sss_iface_addr *dns_addrlist;
bool update_ptr;
bool check_diff;
enum be_nsupdate_auth auth_type;
bool use_server_with_nsupdate;
char *update_msg;
};
bool *_do_update);
struct tevent_req *
struct tevent_context *ev,
struct sdap_id_ctx *sdap_ctx,
enum be_nsupdate_auth auth_type,
const char *ifname,
const char *hostname,
const char *dns_zone,
const char *realm,
const char *servername,
const int ttl,
bool check_diff)
{
struct tevent_req *req;
struct tevent_req *subreq;
struct sdap_dyndns_update_state *state;
return NULL;
}
state->use_server_with_nsupdate = false;
if (ifname) {
/* Unless one family is restricted, just replace all
* address families during the update
*/
case IPV4_ONLY:
break;
case IPV6_ONLY:
break;
case IPV4_FIRST:
case IPV6_FIRST:
break;
}
} else {
/* If the interface isn't specified, we ONLY want to have the address
* that's connected to the LDAP server stored, so we need to check
* (and later remove) both address families.
*/
}
if (!subreq) {
goto done;
}
done:
}
return req;
}
static void
{
struct tevent_req *req;
struct sdap_dyndns_update_state *state;
return;
}
/* Check if we need the update at all. In case we are updating the PTR
* records as well, we need to know the old addresses to be able to
* reliably delete the PTR records */
return;
}
return;
}
/* Perform update */
return;
}
/* Execution will resume in sdap_dyndns_update_done */
}
static void
{
struct tevent_req *req;
struct sdap_dyndns_update_state *state;
bool do_update;
("Could not receive list of current addresses [%d]: %s\n",
return;
}
if (state->check_diff) {
return;
}
if (do_update == false) {
("No DNS update needed, addresses did not change\n"));
return;
}
("Detected IP addresses change, will perform an update\n"));
}
/* Either we needed the addresses for updating PTR records only or
* the addresses have changed (or both) */
}
return;
}
static errno_t
{
int i;
bool do_update;
("Converting DNS IP addresses to strings failed: [%d]: %s\n",
return ret;
}
("Converting local IP addresses to strings failed: [%d]: %s\n",
return ret;
}
/* Compare the lists */
return ret;
}
if (dns_only) {
for (i=0; dns_only[i]; i++) {
("Address in DNS only: %s\n", dns_only[i]));
do_update = true;
}
}
if (local_only) {
for (i=0; local_only[i]; i++) {
("Address on localhost only: %s\n", local_only[i]));
do_update = true;
}
}
*_do_update = do_update;
return EOK;
}
static errno_t
{
struct sdap_dyndns_update_state *state;
const char *servername;
struct tevent_req *subreq;
servername = NULL;
if (state->use_server_with_nsupdate == true &&
state->servername) {
}
&state->update_msg);
return ret;
}
/* Fork a child process to perform the DNS update */
return EIO;
}
return EOK;
}
static void
{
int child_status;
struct tevent_req *req;
struct sdap_dyndns_update_state *state;
/* If the update didn't succeed, we can retry using the server name */
state->use_server_with_nsupdate = true;
("nsupdate failed, retrying with server name\n"));
return;
}
}
return;
}
if (state->update_ptr == false) {
return;
}
return;
}
/* Execution will resume in sdap_dyndns_update_ptr_done */
}
static errno_t
{
struct sdap_dyndns_update_state *state;
const char *servername;
struct tevent_req *subreq;
servername = NULL;
if (state->use_server_with_nsupdate == true &&
state->servername) {
}
&state->update_msg);
return ret;
}
/* Fork a child process to perform the DNS update */
return EIO;
}
return EOK;
}
static void
{
int child_status;
struct tevent_req *req;
struct sdap_dyndns_update_state *state;
/* If the update didn't succeed, we can retry using the server name */
state->use_server_with_nsupdate = true;
("nsupdate failed, retrying with server name\n"));
return;
}
}
return;
}
}
{
return EOK;
}
/* A request to get addresses to update with */
struct sdap_dyndns_get_addrs_state {
struct sdap_id_op* sdap_op;
struct sss_iface_addr *addresses;
};
struct sdap_handle *sh);
static struct tevent_req *
struct tevent_context *ev,
struct sdap_id_ctx *sdap_ctx,
const char *iface)
{
struct tevent_req *req;
struct tevent_req *subreq;
struct sdap_dyndns_get_addrs_state *state;
struct sdap_dyndns_get_addrs_state);
return NULL;
}
if (iface) {
("Cannot get list of addresses from interface %s\n", iface));
}
/* We're done. Just fake an async request completion */
goto done;
}
/* Detect DYNDNS address from LDAP connection */
goto done;
}
if (!subreq) {
goto done;
}
done:
}
/* EAGAIN - resolution in progress */
return req;
}
static void
{
int dp_error;
struct tevent_req *req;
struct sdap_dyndns_get_addrs_state *state;
if (dp_error == DP_ERR_OFFLINE) {
"dynamic DNS update is skipped in offline mode.\n"));
} else {
("Failed to connect to LDAP server: [%d](%s)\n",
}
return;
}
return;
}
/* Got the address! Done! */
}
static errno_t
struct sdap_handle *sh)
{
int ret;
int fd;
struct sss_iface_addr *address;
struct sockaddr_storage ss;
return EINVAL;
}
/* Get the file descriptor for the primary LDAP connection */
return ret;
}
errno = 0;
if (ret == -1) {
return ret;
}
case AF_INET:
case AF_INET6:
return ENOMEM;
}
break;
default:
("Connection to LDAP is neither IPv4 nor IPv6\n"));
return EIO;
}
return EOK;
}
static errno_t
struct sss_iface_addr **_addresses)
{
struct sdap_dyndns_get_addrs_state *state;
return EOK;
}
struct sdap_dyndns_timer_state {
struct tevent_context *ev;
struct sdap_id_ctx *sdap_ctx;
struct be_nsupdate_ctx *dyndns_ctx;
struct sdap_id_op *sdap_op;
};
struct tevent_req *
struct tevent_context *ev,
struct sdap_id_ctx *sdap_ctx,
struct be_nsupdate_ctx *dyndns_ctx)
{
struct sdap_dyndns_timer_state *state;
struct tevent_req *req;
struct tevent_req *subreq;
return NULL;
}
/* In order to prevent the connection triggering an
* online callback which would in turn trigger a concurrent DNS
* update
*/
/* Make sure to have a valid LDAP connection */
goto fail;
}
goto fail;
}
return req;
fail:
dyndns_ctx->timer_in_progress = false;
return req;
}
static void
{
struct tevent_req);
struct sdap_dyndns_timer_state);
int dp_error;
if (dp_error == DP_ERR_OFFLINE) {
"dynamic DNS update is skipped in offline mode.\n"));
/* Another timer will be scheduled when provider goes online */
} else {
("Failed to connect to LDAP server: [%d](%s)\n",
/* Just schedule another dyndns retry */
}
return;
}
/* All OK, schedule another refresh and let the user call its
* provider-specific update
*/
}
{
return EOK;
}