dp_dyndns.c revision 04868f1573f4b26ef34610b6d7069172f93bd8ab
/*
SSSD
Authors:
Stephen Gallagher <sgallagh@redhat.com>
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 <ifaddrs.h>
#include <ctype.h>
#include "util/child_common.h"
#include "providers/data_provider.h"
#include "providers/dp_backend.h"
#include "providers/dp_dyndns.h"
#include "resolv/async_resolv.h"
#ifndef DYNDNS_TIMEOUT
#define DYNDNS_TIMEOUT 15
#endif /* DYNDNS_TIMEOUT */
struct sss_iface_addr {
struct sss_iface_addr *next;
struct sss_iface_addr *prev;
struct sockaddr_storage *addr;
};
struct sss_iface_addr *
struct sockaddr_storage *ss)
{
struct sss_iface_addr *address;
return NULL;
}
sizeof(struct sockaddr_storage));
return NULL;
}
return address;
}
struct sss_iface_addr *ifaddr_list,
char ***_straddrs)
{
struct sss_iface_addr *ifaddr;
int ai;
char **straddrs;
const char *ip;
char ip_addr[INET6_ADDRSTRLEN];
count = 0;
count++;
}
return ENOMEM;
}
ai = 0;
case AF_INET:
errno = 0;
goto fail;
}
break;
case AF_INET6:
errno = 0;
goto fail;
}
break;
default:
continue;
}
goto fail;
}
ai++;
}
return EOK;
fail:
return ret;
}
static bool
{
char straddr[INET6_ADDRSTRLEN];
case AF_INET6:
("inet_ntop failed, won't log IP addresses\n"));
}
if (IN6_IS_ADDR_LINKLOCAL(addr6)) {
return false;
} else if (IN6_IS_ADDR_LOOPBACK(addr6)) {
return false;
} else if (IN6_IS_ADDR_MULTICAST(addr6)) {
return false;
}
break;
case AF_INET:
("inet_ntop failed, won't log IP addresses\n"));
}
return false;
return false;
/* 169.254.0.0/16 */
return false;
return false;
}
break;
default:
return false;
}
return true;
}
/* Collect IP addresses associated with an interface */
struct sss_iface_addr **_addrlist)
{
struct sss_iface_addr *address;
/* Get the IP addresses associated with the
* specified interface
*/
errno = 0;
if (ret == -1) {
goto done;
}
/* Some interfaces don't have an ifa_addr */
/* Add IP addresses to the list */
/* Add this address to the IP address list */
if (!address) {
goto done;
}
sizeof(struct sockaddr_in) : \
sizeof(struct sockaddr_in6);
addrsize);
goto done;
}
}
}
done:
return ret;
}
const char *zone, const char *servername,
char **_update_msg)
{
int ret;
char *realm_directive;
char ip_addr[INET6_ADDRSTRLEN];
const char *ip;
struct sss_iface_addr *new_record;
char *update_msg;
/* in some cases realm could have been NULL if we weren't using TSIG */
return EINVAL;
}
#ifdef HAVE_NSUPDATE_REALM
#else
#endif
if (!realm_directive) {
goto done;
}
/* The realm_directive would now either contain an empty string or be
* completely empty so we don't need to add another newline here
*/
if (servername) {
("Creating update message for server [%s], realm [%s] "
/* Add the server, realm and zone headers */
} else {
("Creating update message for realm [%s] and zone [%s].\n",
/* Add the realm and zone headers */
}
if (update_msg == NULL) {
goto done;
}
/* Remove existing entries as needed */
if (remove_af & DYNDNS_REMOVE_A) {
"update delete %s. in A\nsend\n",
hostname);
if (update_msg == NULL) {
goto done;
}
}
if (remove_af & DYNDNS_REMOVE_AAAA) {
"update delete %s. in AAAA\nsend\n",
hostname);
if (update_msg == NULL) {
goto done;
}
}
case AF_INET:
goto done;
}
break;
case AF_INET6:
goto done;
}
break;
default:
goto done;
}
/* Format the record update */
"update add %s. %d in %s %s\n",
ip_addr);
if (update_msg == NULL) {
goto done;
}
}
if (update_msg == NULL) {
goto done;
}
(" -- Begin nsupdate message -- \n%s",
update_msg));
(" -- End nsupdate message -- \n"));
done:
return ret;
}
struct nsupdate_get_addrs_state {
struct tevent_context *ev;
struct be_resolv_ctx *be_res;
enum host_database *db;
const char *hostname;
/* Use sss_addr in this request */
char **addrlist;
};
struct tevent_req *
struct tevent_context *ev,
struct be_resolv_ctx *be_res,
const char *hostname)
{
struct tevent_req *req;
struct tevent_req *subreq;
struct nsupdate_get_addrs_state *state;
return NULL;
}
goto done;
}
goto done;
}
goto done;
}
done:
}
return req;
}
static void
{
struct tevent_req *req =
struct nsupdate_get_addrs_state);
struct resolv_hostent *rhostent;
int i;
int resolv_status;
&rhostent);
/* If the retry did not match, simply quit */
/* If the resolver is set to honor both address families
* it automatically retries the other one internally, so ENOENT
* means neither matched and we can simply quit.
*/
goto done;
("Could not resolve address for this machine, error [%d]: %s, "
goto done;
}
/* EOK */
} else {
/* The address list is NULL. This is probably a bug in
* c-ares, but we need to handle it gracefully.
*/
("Lookup of [%s] returned no addresses. Skipping.\n",
count = 0;
}
goto done;
}
for (i=0; i < count; i++) {
rhostent, i);
goto done;
}
}
/* If the resolver is set to honor both address families
* and the first one matched, retry the second one to
* get the complete list.
*/
IPV6_ONLY : \
if (!subreq) {
goto done;
}
return;
}
/* The second address matched either immediatelly or after a retry.
* No need to retry again. */
done:
/* All done */
("nsupdate_get_addrs_done failed: [%d]: [%s]\n",
sss_strerror(ret)));
}
/* EAGAIN - another lookup in progress */
}
char ***_addrlist)
{
struct nsupdate_get_addrs_state);
return EOK;
}
/* Write the nsupdate_msg into the already forked child, wait until
* the child finishes
*
* This is not a typical tevent_req styled request as it ends either after
* a timeout or when the child finishes operation.
*/
struct nsupdate_child_state {
int pipefd_to_child;
struct tevent_timer *timeout_handler;
int child_status;
};
static void
struct tevent_timer *te,
static void
struct tevent_signal *sige,
void *pvt);
static struct tevent_req *
struct tevent_context *ev,
int pipefd_to_child,
char *child_stdin)
{
struct tevent_req *req;
struct tevent_req *subreq;
struct nsupdate_child_state *state;
return NULL;
}
/* Set up SIGCHLD handler */
goto done;
}
/* Set up timeout handler */
goto done;
}
/* Write the update message to the nsupdate child */
(uint8_t *) child_stdin,
goto done;
}
done:
}
return req;
}
static void
struct tevent_timer *te,
{
struct tevent_req *req =
struct nsupdate_child_state *state =
}
static void
{
struct tevent_req *req =
struct nsupdate_child_state *state =
/* Verify that the buffer was sent, then return
* and wait for the sigchld handler to finish.
*/
return;
}
/* Now either wait for the timeout to fire or the child
* to finish
*/
}
static void
struct tevent_signal *sige,
void *pvt)
{
struct nsupdate_child_state *state =
("Dynamic DNS child failed with status [%d]\n", child_status));
return;
}
if (WIFSIGNALED(child_status)) {
("Dynamic DNS child was terminated by signal [%d]\n",
WTERMSIG(child_status)));
return;
}
}
static errno_t
{
struct nsupdate_child_state *state =
return ERR_OK;
}
/* Fork a nsupdate child, write the nsupdate_msg into stdin and wait for the child
* to finish one way or another
*/
struct be_nsupdate_state {
int child_status;
};
struct tevent_context *ev,
char *nsupdate_msg)
{
int pipefd_to_child[2];
struct be_nsupdate_state *state;
char *args[3];
return NULL;
}
state->child_status = 0;
if (ret == -1) {
goto done;
}
if (child_pid == 0) { /* child */
goto done;
}
if (ret == -1) {
goto done;
}
errno = 0;
/* The child should never end up here */
goto done;
} else if (child_pid > 0) { /* parent */
close(pipefd_to_child[0]);
goto done;
}
} else { /* error */
goto done;
}
done:
}
return req;
}
static void
{
struct tevent_req *req =
struct be_nsupdate_state *state =
return;
}
}
{
struct be_nsupdate_state *state =
return EOK;
}
be_nsupdate_check(void)
{
/* Ensure that nsupdate exists */
errno = 0;
if (ret == -1) {
("%s does not exist. Dynamic DNS updates disabled\n",
} else {
("Could not set up dynamic DNS updates: [%d][%s]\n",
}
}
return ret;
}
static struct dp_option default_dyndns_opts[] = {
};
{
struct be_nsupdate_ctx *ctx;
return ret;
}
return EOK;
}