From: "Daniel P. Berrange" <berrange@xxxxxxxxxx> --- po/POTFILES.in | 2 +- src/Makefile.am | 2 +- src/network/bridge_driver.c | 2 +- src/network/bridge_driver.h | 2 +- src/util/dnsmasq.c | 872 -------------------------------------------- src/util/dnsmasq.h | 117 ------ src/util/virdnsmasq.c | 872 ++++++++++++++++++++++++++++++++++++++++++++ src/util/virdnsmasq.h | 117 ++++++ 8 files changed, 993 insertions(+), 993 deletions(-) delete mode 100644 src/util/dnsmasq.c delete mode 100644 src/util/dnsmasq.h create mode 100644 src/util/virdnsmasq.c create mode 100644 src/util/virdnsmasq.h diff --git a/po/POTFILES.in b/po/POTFILES.in index e80c413..3214ebe 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -137,7 +137,6 @@ src/storage/storage_driver.c src/test/test_driver.c src/uml/uml_conf.c src/uml/uml_driver.c -src/util/dnsmasq.c src/util/event_poll.c src/util/hooks.c src/util/hostusb.c @@ -158,6 +157,7 @@ src/util/vircgroup.c src/util/vircommand.c src/util/virconf.c src/util/virdbus.c +src/util/virdnsmasq.c src/util/virfile.c src/util/virhash.c src/util/virinitctl.c diff --git a/src/Makefile.am b/src/Makefile.am index b53f1f2..ce16e87 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -58,7 +58,6 @@ UTIL_SOURCES = \ util/hooks.c util/hooks.h \ util/iptables.c util/iptables.h \ util/ebtables.c util/ebtables.h \ - util/dnsmasq.c util/dnsmasq.h \ util/json.c util/json.h \ util/logging.c util/logging.h \ util/memory.c util/memory.h \ @@ -83,6 +82,7 @@ UTIL_SOURCES = \ util/virbuffer.c util/virbuffer.h \ util/vircommand.c util/vircommand.h \ util/virconf.c util/virconf.h \ + util/virdnsmasq.c util/virdnsmasq.h \ util/virfile.c util/virfile.h \ util/virnodesuspend.c util/virnodesuspend.h \ util/virobject.c util/virobject.h \ diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 319ff8c..1110208 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -58,7 +58,7 @@ #include "uuid.h" #include "iptables.h" #include "logging.h" -#include "dnsmasq.h" +#include "virdnsmasq.h" #include "configmake.h" #include "virnetdev.h" #include "pci.h" diff --git a/src/network/bridge_driver.h b/src/network/bridge_driver.h index fea27e0..4bf64ea 100644 --- a/src/network/bridge_driver.h +++ b/src/network/bridge_driver.h @@ -31,7 +31,7 @@ # include "network_conf.h" # include "domain_conf.h" # include "vircommand.h" -# include "dnsmasq.h" +# include "virdnsmasq.h" int networkRegister(void); diff --git a/src/util/dnsmasq.c b/src/util/dnsmasq.c deleted file mode 100644 index 6e9c9dd..0000000 --- a/src/util/dnsmasq.c +++ /dev/null @@ -1,872 +0,0 @@ -/* - * Copyright (C) 2007-2012 Red Hat, Inc. - * Copyright (C) 2010 Satoru SATOH <satoru.satoh@xxxxxxxxx> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * <http://www.gnu.org/licenses/>. - * - * Based on iptables.c - */ - -#include <config.h> - -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <errno.h> -#include <limits.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <signal.h> - -#ifdef HAVE_PATHS_H -# include <paths.h> -#endif - -#include "internal.h" -#include "datatypes.h" -#include "virbitmap.h" -#include "dnsmasq.h" -#include "util.h" -#include "vircommand.h" -#include "memory.h" -#include "virterror_internal.h" -#include "logging.h" -#include "virfile.h" - -#define VIR_FROM_THIS VIR_FROM_NETWORK -#define DNSMASQ_HOSTSFILE_SUFFIX "hostsfile" -#define DNSMASQ_ADDNHOSTSFILE_SUFFIX "addnhosts" - -static void -dhcphostFree(dnsmasqDhcpHost *host) -{ - VIR_FREE(host->host); -} - -static void -addnhostFree(dnsmasqAddnHost *host) -{ - int i; - - for (i = 0; i < host->nhostnames; i++) - VIR_FREE(host->hostnames[i]); - VIR_FREE(host->hostnames); - VIR_FREE(host->ip); -} - -static void -addnhostsFree(dnsmasqAddnHostsfile *addnhostsfile) -{ - unsigned int i; - - if (addnhostsfile->hosts) { - for (i = 0; i < addnhostsfile->nhosts; i++) - addnhostFree(&addnhostsfile->hosts[i]); - - VIR_FREE(addnhostsfile->hosts); - - addnhostsfile->nhosts = 0; - } - - VIR_FREE(addnhostsfile->path); - - VIR_FREE(addnhostsfile); -} - -static int -addnhostsAdd(dnsmasqAddnHostsfile *addnhostsfile, - virSocketAddr *ip, - const char *name) -{ - char *ipstr = NULL; - int idx = -1; - int i; - - if (!(ipstr = virSocketAddrFormat(ip))) - return -1; - - for (i = 0; i < addnhostsfile->nhosts; i++) { - if (STREQ((const char *)addnhostsfile->hosts[i].ip, (const char *)ipstr)) { - idx = i; - break; - } - } - - if (idx < 0) { - if (VIR_REALLOC_N(addnhostsfile->hosts, addnhostsfile->nhosts + 1) < 0) - goto alloc_error; - - idx = addnhostsfile->nhosts; - if (VIR_ALLOC(addnhostsfile->hosts[idx].hostnames) < 0) - goto alloc_error; - - if (virAsprintf(&addnhostsfile->hosts[idx].ip, "%s", ipstr) < 0) - goto alloc_error; - - addnhostsfile->hosts[idx].nhostnames = 0; - addnhostsfile->nhosts++; - } - - if (VIR_REALLOC_N(addnhostsfile->hosts[idx].hostnames, addnhostsfile->hosts[idx].nhostnames + 1) < 0) - goto alloc_error; - - if (virAsprintf(&addnhostsfile->hosts[idx].hostnames[addnhostsfile->hosts[idx].nhostnames], "%s", name) < 0) - goto alloc_error; - - VIR_FREE(ipstr); - - addnhostsfile->hosts[idx].nhostnames++; - - return 0; - - alloc_error: - virReportOOMError(); - VIR_FREE(ipstr); - return -1; -} - -static dnsmasqAddnHostsfile * -addnhostsNew(const char *name, - const char *config_dir) -{ - dnsmasqAddnHostsfile *addnhostsfile; - - if (VIR_ALLOC(addnhostsfile) < 0) { - virReportOOMError(); - return NULL; - } - - addnhostsfile->hosts = NULL; - addnhostsfile->nhosts = 0; - - if (virAsprintf(&addnhostsfile->path, "%s/%s.%s", config_dir, name, - DNSMASQ_ADDNHOSTSFILE_SUFFIX) < 0) { - virReportOOMError(); - goto error; - } - - return addnhostsfile; - - error: - addnhostsFree(addnhostsfile); - return NULL; -} - -static int -addnhostsWrite(const char *path, - dnsmasqAddnHost *hosts, - unsigned int nhosts) -{ - char *tmp; - FILE *f; - bool istmp = true; - unsigned int i, ii; - int rc = 0; - - /* even if there are 0 hosts, create a 0 length file, to allow - * for runtime addition. - */ - - if (virAsprintf(&tmp, "%s.new", path) < 0) - return -ENOMEM; - - if (!(f = fopen(tmp, "w"))) { - istmp = false; - if (!(f = fopen(path, "w"))) { - rc = -errno; - goto cleanup; - } - } - - for (i = 0; i < nhosts; i++) { - if (fputs(hosts[i].ip, f) == EOF || fputc('\t', f) == EOF) { - rc = -errno; - VIR_FORCE_FCLOSE(f); - - if (istmp) - unlink(tmp); - - goto cleanup; - } - - for (ii = 0; ii < hosts[i].nhostnames; ii++) { - if (fputs(hosts[i].hostnames[ii], f) == EOF || fputc('\t', f) == EOF) { - rc = -errno; - VIR_FORCE_FCLOSE(f); - - if (istmp) - unlink(tmp); - - goto cleanup; - } - } - - if (fputc('\n', f) == EOF) { - rc = -errno; - VIR_FORCE_FCLOSE(f); - - if (istmp) - unlink(tmp); - - goto cleanup; - } - } - - if (VIR_FCLOSE(f) == EOF) { - rc = -errno; - goto cleanup; - } - - if (istmp && rename(tmp, path) < 0) { - rc = -errno; - unlink(tmp); - goto cleanup; - } - - cleanup: - VIR_FREE(tmp); - - return rc; -} - -static int -addnhostsSave(dnsmasqAddnHostsfile *addnhostsfile) -{ - int err = addnhostsWrite(addnhostsfile->path, addnhostsfile->hosts, - addnhostsfile->nhosts); - - if (err < 0) { - virReportSystemError(-err, _("cannot write config file '%s'"), - addnhostsfile->path); - return -1; - } - - return 0; -} - -static int -genericFileDelete(char *path) -{ - if (!virFileExists(path)) - return 0; - - if (unlink(path) < 0) { - virReportSystemError(errno, _("cannot remove config file '%s'"), - path); - return -1; - } - - return 0; -} - -static void -hostsfileFree(dnsmasqHostsfile *hostsfile) -{ - unsigned int i; - - if (hostsfile->hosts) { - for (i = 0; i < hostsfile->nhosts; i++) - dhcphostFree(&hostsfile->hosts[i]); - - VIR_FREE(hostsfile->hosts); - - hostsfile->nhosts = 0; - } - - VIR_FREE(hostsfile->path); - - VIR_FREE(hostsfile); -} - -/* Note: There are many additional dhcp-host specifications - * supported by dnsmasq. There are only the basic ones. - */ -static int -hostsfileAdd(dnsmasqHostsfile *hostsfile, - const char *mac, - virSocketAddr *ip, - const char *name, - bool ipv6) -{ - char *ipstr = NULL; - if (VIR_REALLOC_N(hostsfile->hosts, hostsfile->nhosts + 1) < 0) - goto alloc_error; - - if (!(ipstr = virSocketAddrFormat(ip))) - return -1; - - /* the first test determines if it is a dhcpv6 host */ - if (ipv6) { - if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,[%s]", - name, ipstr) < 0) - goto alloc_error; - } - else if (name && mac) { - if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s,%s", - mac, ipstr, name) < 0) - goto alloc_error; - } else if (name && !mac){ - if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s", - name, ipstr) < 0) - goto alloc_error; - } else { - if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s", - mac, ipstr) < 0) - goto alloc_error; - } - VIR_FREE(ipstr); - - hostsfile->nhosts++; - - return 0; - - alloc_error: - virReportOOMError(); - VIR_FREE(ipstr); - return -1; -} - -static dnsmasqHostsfile * -hostsfileNew(const char *name, - const char *config_dir) -{ - dnsmasqHostsfile *hostsfile; - - if (VIR_ALLOC(hostsfile) < 0) { - virReportOOMError(); - return NULL; - } - - hostsfile->hosts = NULL; - hostsfile->nhosts = 0; - - if (virAsprintf(&hostsfile->path, "%s/%s.%s", config_dir, name, - DNSMASQ_HOSTSFILE_SUFFIX) < 0) { - virReportOOMError(); - goto error; - } - - return hostsfile; - - error: - hostsfileFree(hostsfile); - return NULL; -} - -static int -hostsfileWrite(const char *path, - dnsmasqDhcpHost *hosts, - unsigned int nhosts) -{ - char *tmp; - FILE *f; - bool istmp = true; - unsigned int i; - int rc = 0; - - /* even if there are 0 hosts, create a 0 length file, to allow - * for runtime addition. - */ - - if (virAsprintf(&tmp, "%s.new", path) < 0) - return -ENOMEM; - - if (!(f = fopen(tmp, "w"))) { - istmp = false; - if (!(f = fopen(path, "w"))) { - rc = -errno; - goto cleanup; - } - } - - for (i = 0; i < nhosts; i++) { - if (fputs(hosts[i].host, f) == EOF || fputc('\n', f) == EOF) { - rc = -errno; - VIR_FORCE_FCLOSE(f); - - if (istmp) - unlink(tmp); - - goto cleanup; - } - } - - if (VIR_FCLOSE(f) == EOF) { - rc = -errno; - goto cleanup; - } - - if (istmp && rename(tmp, path) < 0) { - rc = -errno; - unlink(tmp); - goto cleanup; - } - - cleanup: - VIR_FREE(tmp); - - return rc; -} - -static int -hostsfileSave(dnsmasqHostsfile *hostsfile) -{ - int err = hostsfileWrite(hostsfile->path, hostsfile->hosts, - hostsfile->nhosts); - - if (err < 0) { - virReportSystemError(-err, _("cannot write config file '%s'"), - hostsfile->path); - return -1; - } - - return 0; -} - -/** - * dnsmasqContextNew: - * - * Create a new Dnsmasq context - * - * Returns a pointer to the new structure or NULL in case of error - */ -dnsmasqContext * -dnsmasqContextNew(const char *network_name, - const char *config_dir) -{ - dnsmasqContext *ctx; - - if (VIR_ALLOC(ctx) < 0) { - virReportOOMError(); - return NULL; - } - - if (!(ctx->config_dir = strdup(config_dir))) { - virReportOOMError(); - goto error; - } - - if (!(ctx->hostsfile = hostsfileNew(network_name, config_dir))) - goto error; - if (!(ctx->addnhostsfile = addnhostsNew(network_name, config_dir))) - goto error; - - return ctx; - - error: - dnsmasqContextFree(ctx); - return NULL; -} - -/** - * dnsmasqContextFree: - * @ctx: pointer to the dnsmasq context - * - * Free the resources associated with a dnsmasq context - */ -void -dnsmasqContextFree(dnsmasqContext *ctx) -{ - if (!ctx) - return; - - VIR_FREE(ctx->config_dir); - - if (ctx->hostsfile) - hostsfileFree(ctx->hostsfile); - if (ctx->addnhostsfile) - addnhostsFree(ctx->addnhostsfile); - - VIR_FREE(ctx); -} - -/** - * dnsmasqAddDhcpHost: - * @ctx: pointer to the dnsmasq context for each network - * @mac: pointer to the string contains mac address of the host - * @ip: pointer to the socket address contains ip of the host - * @name: pointer to the string contains hostname of the host or NULL - * - * Add dhcp-host entry. - */ -int -dnsmasqAddDhcpHost(dnsmasqContext *ctx, - const char *mac, - virSocketAddr *ip, - const char *name, - bool ipv6) -{ - return hostsfileAdd(ctx->hostsfile, mac, ip, name, ipv6); -} - -/* - * dnsmasqAddHost: - * @ctx: pointer to the dnsmasq context for each network - * @ip: pointer to the socket address contains ip of the host - * @name: pointer to the string contains hostname of the host - * - * Add additional host entry. - */ - -int -dnsmasqAddHost(dnsmasqContext *ctx, - virSocketAddr *ip, - const char *name) -{ - return addnhostsAdd(ctx->addnhostsfile, ip, name); -} - -/** - * dnsmasqSave: - * @ctx: pointer to the dnsmasq context for each network - * - * Saves all the configurations associated with a context to disk. - */ -int -dnsmasqSave(const dnsmasqContext *ctx) -{ - int ret = 0; - - if (virFileMakePath(ctx->config_dir) < 0) { - virReportSystemError(errno, _("cannot create config directory '%s'"), - ctx->config_dir); - return -1; - } - - if (ctx->hostsfile) - ret = hostsfileSave(ctx->hostsfile); - if (ret == 0) { - if (ctx->addnhostsfile) - ret = addnhostsSave(ctx->addnhostsfile); - } - - return ret; -} - - -/** - * dnsmasqDelete: - * @ctx: pointer to the dnsmasq context for each network - * - * Delete all the configuration files associated with a context. - */ -int -dnsmasqDelete(const dnsmasqContext *ctx) -{ - int ret = 0; - - if (ctx->hostsfile) - ret = genericFileDelete(ctx->hostsfile->path); - if (ctx->addnhostsfile) - ret = genericFileDelete(ctx->addnhostsfile->path); - - return ret; -} - -/** - * dnsmasqReload: - * @pid: the pid of the target dnsmasq process - * - * Reloads all the configurations associated to a context - */ -int -dnsmasqReload(pid_t pid ATTRIBUTE_UNUSED) -{ -#ifndef WIN32 - if (kill(pid, SIGHUP) != 0) { - virReportSystemError(errno, - _("Failed to make dnsmasq (PID: %d) reload config files."), - pid); - return -1; - } -#endif /* WIN32 */ - - return 0; -} - -/* - * dnsmasqCapabilities functions - provide useful information about the - * version of dnsmasq on this machine. - * - */ -struct _dnsmasqCaps { - virObject object; - char *binaryPath; - bool noRefresh; - time_t mtime; - virBitmapPtr flags; - unsigned long version; -}; - -static virClassPtr dnsmasqCapsClass; - -static void -dnsmasqCapsDispose(void *obj) -{ - dnsmasqCapsPtr caps = obj; - - virBitmapFree(caps->flags); - VIR_FREE(caps->binaryPath); -} - -static int dnsmasqCapsOnceInit(void) -{ - if (!(dnsmasqCapsClass = virClassNew("dnsmasqCaps", - sizeof(dnsmasqCaps), - dnsmasqCapsDispose))) { - return -1; - } - - return 0; -} - -VIR_ONCE_GLOBAL_INIT(dnsmasqCaps) - -static void -dnsmasqCapsSet(dnsmasqCapsPtr caps, - dnsmasqCapsFlags flag) -{ - ignore_value(virBitmapSetBit(caps->flags, flag)); -} - - -#define DNSMASQ_VERSION_STR "Dnsmasq version " - -static int -dnsmasqCapsSetFromBuffer(dnsmasqCapsPtr caps, const char *buf) -{ - const char *p; - - caps->noRefresh = true; - - p = STRSKIP(buf, DNSMASQ_VERSION_STR); - if (!p) - goto fail; - virSkipSpaces(&p); - if (virParseVersionString(p, &caps->version, true) < 0) - goto fail; - - if (strstr(buf, "--bind-dynamic")) - dnsmasqCapsSet(caps, DNSMASQ_CAPS_BIND_DYNAMIC); - - VIR_INFO("dnsmasq version is %d.%d, --bind-dynamic is %s", - (int)caps->version / 1000000, (int)(caps->version % 1000000) / 1000, - dnsmasqCapsGet(caps, DNSMASQ_CAPS_BIND_DYNAMIC) - ? "present" : "NOT present"); - return 0; - -fail: - p = strchrnul(buf, '\n'); - virReportError(VIR_ERR_INTERNAL_ERROR, - _("cannot parse %s version number in '%.*s'"), - caps->binaryPath, (int) (p - buf), buf); - return -1; - -} - -static int -dnsmasqCapsSetFromFile(dnsmasqCapsPtr caps, const char *path) -{ - int ret = -1; - char *buf = NULL; - - if (virFileReadAll(path, 1024 * 1024, &buf) < 0) - goto cleanup; - - ret = dnsmasqCapsSetFromBuffer(caps, buf); - -cleanup: - VIR_FREE(buf); - return ret; -} - -static int -dnsmasqCapsRefreshInternal(dnsmasqCapsPtr caps, bool force) -{ - int ret = -1; - struct stat sb; - virCommandPtr cmd = NULL; - char *help = NULL, *version = NULL, *complete = NULL; - - if (!caps || caps->noRefresh) - return 0; - - if (stat(caps->binaryPath, &sb) < 0) { - virReportSystemError(errno, _("Cannot check dnsmasq binary %s"), - caps->binaryPath); - return -1; - } - if (!force && caps->mtime == sb.st_mtime) { - return 0; - } - caps->mtime = sb.st_mtime; - - /* Make sure the binary we are about to try exec'ing exists. - * Technically we could catch the exec() failure, but that's - * in a sub-process so it's hard to feed back a useful error. - */ - if (!virFileIsExecutable(caps->binaryPath)) { - virReportSystemError(errno, _("dnsmasq binary %s is not executable"), - caps->binaryPath); - goto cleanup; - } - - cmd = virCommandNewArgList(caps->binaryPath, "--version", NULL); - virCommandSetOutputBuffer(cmd, &version); - virCommandAddEnvPassCommon(cmd); - virCommandClearCaps(cmd); - if (virCommandRun(cmd, NULL) < 0) { - virReportSystemError(errno, _("failed to run '%s --version': %s"), - caps->binaryPath, version); - goto cleanup; - } - virCommandFree(cmd); - - cmd = virCommandNewArgList(caps->binaryPath, "--help", NULL); - virCommandSetOutputBuffer(cmd, &help); - virCommandAddEnvPassCommon(cmd); - virCommandClearCaps(cmd); - if (virCommandRun(cmd, NULL) < 0) { - virReportSystemError(errno, _("failed to run '%s --help': %s"), - caps->binaryPath, help); - goto cleanup; - } - - if (virAsprintf(&complete, "%s\n%s", version, help) < 0) { - virReportOOMError(); - goto cleanup; - } - - ret = dnsmasqCapsSetFromBuffer(caps, complete); - -cleanup: - virCommandFree(cmd); - VIR_FREE(help); - VIR_FREE(version); - VIR_FREE(complete); - return ret; -} - -static dnsmasqCapsPtr -dnsmasqCapsNewEmpty(const char *binaryPath) -{ - dnsmasqCapsPtr caps; - - if (dnsmasqCapsInitialize() < 0) - return NULL; - if (!(caps = virObjectNew(dnsmasqCapsClass))) - return NULL; - if (!(caps->flags = virBitmapNew(DNSMASQ_CAPS_LAST))) - goto error; - if (!(caps->binaryPath = strdup(binaryPath ? binaryPath : DNSMASQ))) - goto error; - return caps; - -error: - virReportOOMError(); - virObjectUnref(caps); - return NULL; -} - -dnsmasqCapsPtr -dnsmasqCapsNewFromBuffer(const char *buf, const char *binaryPath) -{ - dnsmasqCapsPtr caps = dnsmasqCapsNewEmpty(binaryPath); - - if (!caps) - return NULL; - - if (dnsmasqCapsSetFromBuffer(caps, buf) < 0) { - virObjectUnref(caps); - return NULL; - } - return caps; -} - -dnsmasqCapsPtr -dnsmasqCapsNewFromFile(const char *dataPath, const char *binaryPath) -{ - dnsmasqCapsPtr caps = dnsmasqCapsNewEmpty(binaryPath); - - if (!caps) - return NULL; - - if (dnsmasqCapsSetFromFile(caps, dataPath) < 0) { - virObjectUnref(caps); - return NULL; - } - return caps; -} - -dnsmasqCapsPtr -dnsmasqCapsNewFromBinary(const char *binaryPath) -{ - dnsmasqCapsPtr caps = dnsmasqCapsNewEmpty(binaryPath); - - if (!caps) - return NULL; - - if (dnsmasqCapsRefreshInternal(caps, true) < 0) { - virObjectUnref(caps); - return NULL; - } - return caps; -} - -/** dnsmasqCapsRefresh: - * - * Refresh an existing caps object if the binary has changed. If - * there isn't yet a caps object (if it's NULL), create a new one. - * - * Returns 0 on success, -1 on failure - */ -int -dnsmasqCapsRefresh(dnsmasqCapsPtr *caps, const char *binaryPath) -{ - if (!*caps) { - *caps = dnsmasqCapsNewFromBinary(binaryPath); - return *caps ? 0 : -1; - } - return dnsmasqCapsRefreshInternal(*caps, false); -} - -const char * -dnsmasqCapsGetBinaryPath(dnsmasqCapsPtr caps) -{ - return caps ? caps->binaryPath : DNSMASQ; -} - -unsigned long -dnsmasqCapsGetVersion(dnsmasqCapsPtr caps) -{ - if (caps) - return caps->version; - else - return 0; -} - -bool -dnsmasqCapsGet(dnsmasqCapsPtr caps, dnsmasqCapsFlags flag) -{ - bool b; - - if (!caps || virBitmapGetBit(caps->flags, flag, &b) < 0) - return false; - else - return b; -} diff --git a/src/util/dnsmasq.h b/src/util/dnsmasq.h deleted file mode 100644 index 7a39232..0000000 --- a/src/util/dnsmasq.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2007-2012 Red Hat, Inc. - * Copyright (C) 2010 Satoru SATOH <satoru.satoh@xxxxxxxxx> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * <http://www.gnu.org/licenses/>. - * - * based on iptables.h - */ - -#ifndef __DNSMASQ_H__ -# define __DNSMASQ_H__ - -# include "virobject.h" -# include "virsocketaddr.h" - -typedef struct -{ - /* - * Each entry holds a string, "<mac_addr>,<hostname>,<ip_addr>" such as - * "01:23:45:67:89:0a,foo,10.0.0.3". - */ - char *host; - -} dnsmasqDhcpHost; - -typedef struct -{ - unsigned int nhosts; - dnsmasqDhcpHost *hosts; - - char *path; /* Absolute path of dnsmasq's hostsfile. */ -} dnsmasqHostsfile; - -typedef struct -{ - unsigned int nhostnames; - char *ip; - char **hostnames; - -} dnsmasqAddnHost; - -typedef struct -{ - unsigned int nhosts; - dnsmasqAddnHost *hosts; - - char *path; /* Absolute path of dnsmasq's hostsfile. */ -} dnsmasqAddnHostsfile; - -typedef struct -{ - char *config_dir; - dnsmasqHostsfile *hostsfile; - dnsmasqAddnHostsfile *addnhostsfile; -} dnsmasqContext; - -typedef enum { - DNSMASQ_CAPS_BIND_DYNAMIC = 0, /* support for --bind-dynamic */ - - DNSMASQ_CAPS_LAST, /* this must always be the last item */ -} dnsmasqCapsFlags; - -typedef struct _dnsmasqCaps dnsmasqCaps; -typedef dnsmasqCaps *dnsmasqCapsPtr; - - -dnsmasqContext * dnsmasqContextNew(const char *network_name, - const char *config_dir); -void dnsmasqContextFree(dnsmasqContext *ctx); -int dnsmasqAddDhcpHost(dnsmasqContext *ctx, - const char *mac, - virSocketAddr *ip, - const char *name, - bool ipv6); -int dnsmasqAddHost(dnsmasqContext *ctx, - virSocketAddr *ip, - const char *name); -int dnsmasqSave(const dnsmasqContext *ctx); -int dnsmasqDelete(const dnsmasqContext *ctx); -int dnsmasqReload(pid_t pid); - -dnsmasqCapsPtr dnsmasqCapsNewFromBuffer(const char *buf, - const char *binaryPath); -dnsmasqCapsPtr dnsmasqCapsNewFromFile(const char *dataPath, - const char *binaryPath); -dnsmasqCapsPtr dnsmasqCapsNewFromBinary(const char *binaryPath); -int dnsmasqCapsRefresh(dnsmasqCapsPtr *caps, const char *binaryPath); -bool dnsmasqCapsGet(dnsmasqCapsPtr caps, dnsmasqCapsFlags flag); -const char *dnsmasqCapsGetBinaryPath(dnsmasqCapsPtr caps); -unsigned long dnsmasqCapsGetVersion(dnsmasqCapsPtr caps); - -# define DNSMASQ_DHCPv6_MAJOR_REQD 2 -# define DNSMASQ_DHCPv6_MINOR_REQD 64 -# define DNSMASQ_RA_MAJOR_REQD 2 -# define DNSMASQ_RA_MINOR_REQD 64 - -# define DNSMASQ_DHCPv6_SUPPORT(CAPS) \ - (dnsmasqCapsGetVersion(CAPS) >= \ - (DNSMASQ_DHCPv6_MAJOR_REQD * 1000000) + \ - (DNSMASQ_DHCPv6_MINOR_REQD * 1000)) -# define DNSMASQ_RA_SUPPORT(CAPS) \ - (dnsmasqCapsGetVersion(CAPS) >= \ - (DNSMASQ_RA_MAJOR_REQD * 1000000) + \ - (DNSMASQ_RA_MINOR_REQD * 1000)) -#endif /* __DNSMASQ_H__ */ diff --git a/src/util/virdnsmasq.c b/src/util/virdnsmasq.c new file mode 100644 index 0000000..4a32f49 --- /dev/null +++ b/src/util/virdnsmasq.c @@ -0,0 +1,872 @@ +/* + * Copyright (C) 2007-2012 Red Hat, Inc. + * Copyright (C) 2010 Satoru SATOH <satoru.satoh@xxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Based on iptables.c + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <errno.h> +#include <limits.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <signal.h> + +#ifdef HAVE_PATHS_H +# include <paths.h> +#endif + +#include "internal.h" +#include "datatypes.h" +#include "virbitmap.h" +#include "virdnsmasq.h" +#include "util.h" +#include "vircommand.h" +#include "memory.h" +#include "virterror_internal.h" +#include "logging.h" +#include "virfile.h" + +#define VIR_FROM_THIS VIR_FROM_NETWORK +#define DNSMASQ_HOSTSFILE_SUFFIX "hostsfile" +#define DNSMASQ_ADDNHOSTSFILE_SUFFIX "addnhosts" + +static void +dhcphostFree(dnsmasqDhcpHost *host) +{ + VIR_FREE(host->host); +} + +static void +addnhostFree(dnsmasqAddnHost *host) +{ + int i; + + for (i = 0; i < host->nhostnames; i++) + VIR_FREE(host->hostnames[i]); + VIR_FREE(host->hostnames); + VIR_FREE(host->ip); +} + +static void +addnhostsFree(dnsmasqAddnHostsfile *addnhostsfile) +{ + unsigned int i; + + if (addnhostsfile->hosts) { + for (i = 0; i < addnhostsfile->nhosts; i++) + addnhostFree(&addnhostsfile->hosts[i]); + + VIR_FREE(addnhostsfile->hosts); + + addnhostsfile->nhosts = 0; + } + + VIR_FREE(addnhostsfile->path); + + VIR_FREE(addnhostsfile); +} + +static int +addnhostsAdd(dnsmasqAddnHostsfile *addnhostsfile, + virSocketAddr *ip, + const char *name) +{ + char *ipstr = NULL; + int idx = -1; + int i; + + if (!(ipstr = virSocketAddrFormat(ip))) + return -1; + + for (i = 0; i < addnhostsfile->nhosts; i++) { + if (STREQ((const char *)addnhostsfile->hosts[i].ip, (const char *)ipstr)) { + idx = i; + break; + } + } + + if (idx < 0) { + if (VIR_REALLOC_N(addnhostsfile->hosts, addnhostsfile->nhosts + 1) < 0) + goto alloc_error; + + idx = addnhostsfile->nhosts; + if (VIR_ALLOC(addnhostsfile->hosts[idx].hostnames) < 0) + goto alloc_error; + + if (virAsprintf(&addnhostsfile->hosts[idx].ip, "%s", ipstr) < 0) + goto alloc_error; + + addnhostsfile->hosts[idx].nhostnames = 0; + addnhostsfile->nhosts++; + } + + if (VIR_REALLOC_N(addnhostsfile->hosts[idx].hostnames, addnhostsfile->hosts[idx].nhostnames + 1) < 0) + goto alloc_error; + + if (virAsprintf(&addnhostsfile->hosts[idx].hostnames[addnhostsfile->hosts[idx].nhostnames], "%s", name) < 0) + goto alloc_error; + + VIR_FREE(ipstr); + + addnhostsfile->hosts[idx].nhostnames++; + + return 0; + + alloc_error: + virReportOOMError(); + VIR_FREE(ipstr); + return -1; +} + +static dnsmasqAddnHostsfile * +addnhostsNew(const char *name, + const char *config_dir) +{ + dnsmasqAddnHostsfile *addnhostsfile; + + if (VIR_ALLOC(addnhostsfile) < 0) { + virReportOOMError(); + return NULL; + } + + addnhostsfile->hosts = NULL; + addnhostsfile->nhosts = 0; + + if (virAsprintf(&addnhostsfile->path, "%s/%s.%s", config_dir, name, + DNSMASQ_ADDNHOSTSFILE_SUFFIX) < 0) { + virReportOOMError(); + goto error; + } + + return addnhostsfile; + + error: + addnhostsFree(addnhostsfile); + return NULL; +} + +static int +addnhostsWrite(const char *path, + dnsmasqAddnHost *hosts, + unsigned int nhosts) +{ + char *tmp; + FILE *f; + bool istmp = true; + unsigned int i, ii; + int rc = 0; + + /* even if there are 0 hosts, create a 0 length file, to allow + * for runtime addition. + */ + + if (virAsprintf(&tmp, "%s.new", path) < 0) + return -ENOMEM; + + if (!(f = fopen(tmp, "w"))) { + istmp = false; + if (!(f = fopen(path, "w"))) { + rc = -errno; + goto cleanup; + } + } + + for (i = 0; i < nhosts; i++) { + if (fputs(hosts[i].ip, f) == EOF || fputc('\t', f) == EOF) { + rc = -errno; + VIR_FORCE_FCLOSE(f); + + if (istmp) + unlink(tmp); + + goto cleanup; + } + + for (ii = 0; ii < hosts[i].nhostnames; ii++) { + if (fputs(hosts[i].hostnames[ii], f) == EOF || fputc('\t', f) == EOF) { + rc = -errno; + VIR_FORCE_FCLOSE(f); + + if (istmp) + unlink(tmp); + + goto cleanup; + } + } + + if (fputc('\n', f) == EOF) { + rc = -errno; + VIR_FORCE_FCLOSE(f); + + if (istmp) + unlink(tmp); + + goto cleanup; + } + } + + if (VIR_FCLOSE(f) == EOF) { + rc = -errno; + goto cleanup; + } + + if (istmp && rename(tmp, path) < 0) { + rc = -errno; + unlink(tmp); + goto cleanup; + } + + cleanup: + VIR_FREE(tmp); + + return rc; +} + +static int +addnhostsSave(dnsmasqAddnHostsfile *addnhostsfile) +{ + int err = addnhostsWrite(addnhostsfile->path, addnhostsfile->hosts, + addnhostsfile->nhosts); + + if (err < 0) { + virReportSystemError(-err, _("cannot write config file '%s'"), + addnhostsfile->path); + return -1; + } + + return 0; +} + +static int +genericFileDelete(char *path) +{ + if (!virFileExists(path)) + return 0; + + if (unlink(path) < 0) { + virReportSystemError(errno, _("cannot remove config file '%s'"), + path); + return -1; + } + + return 0; +} + +static void +hostsfileFree(dnsmasqHostsfile *hostsfile) +{ + unsigned int i; + + if (hostsfile->hosts) { + for (i = 0; i < hostsfile->nhosts; i++) + dhcphostFree(&hostsfile->hosts[i]); + + VIR_FREE(hostsfile->hosts); + + hostsfile->nhosts = 0; + } + + VIR_FREE(hostsfile->path); + + VIR_FREE(hostsfile); +} + +/* Note: There are many additional dhcp-host specifications + * supported by dnsmasq. There are only the basic ones. + */ +static int +hostsfileAdd(dnsmasqHostsfile *hostsfile, + const char *mac, + virSocketAddr *ip, + const char *name, + bool ipv6) +{ + char *ipstr = NULL; + if (VIR_REALLOC_N(hostsfile->hosts, hostsfile->nhosts + 1) < 0) + goto alloc_error; + + if (!(ipstr = virSocketAddrFormat(ip))) + return -1; + + /* the first test determines if it is a dhcpv6 host */ + if (ipv6) { + if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,[%s]", + name, ipstr) < 0) + goto alloc_error; + } + else if (name && mac) { + if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s,%s", + mac, ipstr, name) < 0) + goto alloc_error; + } else if (name && !mac){ + if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s", + name, ipstr) < 0) + goto alloc_error; + } else { + if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s", + mac, ipstr) < 0) + goto alloc_error; + } + VIR_FREE(ipstr); + + hostsfile->nhosts++; + + return 0; + + alloc_error: + virReportOOMError(); + VIR_FREE(ipstr); + return -1; +} + +static dnsmasqHostsfile * +hostsfileNew(const char *name, + const char *config_dir) +{ + dnsmasqHostsfile *hostsfile; + + if (VIR_ALLOC(hostsfile) < 0) { + virReportOOMError(); + return NULL; + } + + hostsfile->hosts = NULL; + hostsfile->nhosts = 0; + + if (virAsprintf(&hostsfile->path, "%s/%s.%s", config_dir, name, + DNSMASQ_HOSTSFILE_SUFFIX) < 0) { + virReportOOMError(); + goto error; + } + + return hostsfile; + + error: + hostsfileFree(hostsfile); + return NULL; +} + +static int +hostsfileWrite(const char *path, + dnsmasqDhcpHost *hosts, + unsigned int nhosts) +{ + char *tmp; + FILE *f; + bool istmp = true; + unsigned int i; + int rc = 0; + + /* even if there are 0 hosts, create a 0 length file, to allow + * for runtime addition. + */ + + if (virAsprintf(&tmp, "%s.new", path) < 0) + return -ENOMEM; + + if (!(f = fopen(tmp, "w"))) { + istmp = false; + if (!(f = fopen(path, "w"))) { + rc = -errno; + goto cleanup; + } + } + + for (i = 0; i < nhosts; i++) { + if (fputs(hosts[i].host, f) == EOF || fputc('\n', f) == EOF) { + rc = -errno; + VIR_FORCE_FCLOSE(f); + + if (istmp) + unlink(tmp); + + goto cleanup; + } + } + + if (VIR_FCLOSE(f) == EOF) { + rc = -errno; + goto cleanup; + } + + if (istmp && rename(tmp, path) < 0) { + rc = -errno; + unlink(tmp); + goto cleanup; + } + + cleanup: + VIR_FREE(tmp); + + return rc; +} + +static int +hostsfileSave(dnsmasqHostsfile *hostsfile) +{ + int err = hostsfileWrite(hostsfile->path, hostsfile->hosts, + hostsfile->nhosts); + + if (err < 0) { + virReportSystemError(-err, _("cannot write config file '%s'"), + hostsfile->path); + return -1; + } + + return 0; +} + +/** + * dnsmasqContextNew: + * + * Create a new Dnsmasq context + * + * Returns a pointer to the new structure or NULL in case of error + */ +dnsmasqContext * +dnsmasqContextNew(const char *network_name, + const char *config_dir) +{ + dnsmasqContext *ctx; + + if (VIR_ALLOC(ctx) < 0) { + virReportOOMError(); + return NULL; + } + + if (!(ctx->config_dir = strdup(config_dir))) { + virReportOOMError(); + goto error; + } + + if (!(ctx->hostsfile = hostsfileNew(network_name, config_dir))) + goto error; + if (!(ctx->addnhostsfile = addnhostsNew(network_name, config_dir))) + goto error; + + return ctx; + + error: + dnsmasqContextFree(ctx); + return NULL; +} + +/** + * dnsmasqContextFree: + * @ctx: pointer to the dnsmasq context + * + * Free the resources associated with a dnsmasq context + */ +void +dnsmasqContextFree(dnsmasqContext *ctx) +{ + if (!ctx) + return; + + VIR_FREE(ctx->config_dir); + + if (ctx->hostsfile) + hostsfileFree(ctx->hostsfile); + if (ctx->addnhostsfile) + addnhostsFree(ctx->addnhostsfile); + + VIR_FREE(ctx); +} + +/** + * dnsmasqAddDhcpHost: + * @ctx: pointer to the dnsmasq context for each network + * @mac: pointer to the string contains mac address of the host + * @ip: pointer to the socket address contains ip of the host + * @name: pointer to the string contains hostname of the host or NULL + * + * Add dhcp-host entry. + */ +int +dnsmasqAddDhcpHost(dnsmasqContext *ctx, + const char *mac, + virSocketAddr *ip, + const char *name, + bool ipv6) +{ + return hostsfileAdd(ctx->hostsfile, mac, ip, name, ipv6); +} + +/* + * dnsmasqAddHost: + * @ctx: pointer to the dnsmasq context for each network + * @ip: pointer to the socket address contains ip of the host + * @name: pointer to the string contains hostname of the host + * + * Add additional host entry. + */ + +int +dnsmasqAddHost(dnsmasqContext *ctx, + virSocketAddr *ip, + const char *name) +{ + return addnhostsAdd(ctx->addnhostsfile, ip, name); +} + +/** + * dnsmasqSave: + * @ctx: pointer to the dnsmasq context for each network + * + * Saves all the configurations associated with a context to disk. + */ +int +dnsmasqSave(const dnsmasqContext *ctx) +{ + int ret = 0; + + if (virFileMakePath(ctx->config_dir) < 0) { + virReportSystemError(errno, _("cannot create config directory '%s'"), + ctx->config_dir); + return -1; + } + + if (ctx->hostsfile) + ret = hostsfileSave(ctx->hostsfile); + if (ret == 0) { + if (ctx->addnhostsfile) + ret = addnhostsSave(ctx->addnhostsfile); + } + + return ret; +} + + +/** + * dnsmasqDelete: + * @ctx: pointer to the dnsmasq context for each network + * + * Delete all the configuration files associated with a context. + */ +int +dnsmasqDelete(const dnsmasqContext *ctx) +{ + int ret = 0; + + if (ctx->hostsfile) + ret = genericFileDelete(ctx->hostsfile->path); + if (ctx->addnhostsfile) + ret = genericFileDelete(ctx->addnhostsfile->path); + + return ret; +} + +/** + * dnsmasqReload: + * @pid: the pid of the target dnsmasq process + * + * Reloads all the configurations associated to a context + */ +int +dnsmasqReload(pid_t pid ATTRIBUTE_UNUSED) +{ +#ifndef WIN32 + if (kill(pid, SIGHUP) != 0) { + virReportSystemError(errno, + _("Failed to make dnsmasq (PID: %d) reload config files."), + pid); + return -1; + } +#endif /* WIN32 */ + + return 0; +} + +/* + * dnsmasqCapabilities functions - provide useful information about the + * version of dnsmasq on this machine. + * + */ +struct _dnsmasqCaps { + virObject object; + char *binaryPath; + bool noRefresh; + time_t mtime; + virBitmapPtr flags; + unsigned long version; +}; + +static virClassPtr dnsmasqCapsClass; + +static void +dnsmasqCapsDispose(void *obj) +{ + dnsmasqCapsPtr caps = obj; + + virBitmapFree(caps->flags); + VIR_FREE(caps->binaryPath); +} + +static int dnsmasqCapsOnceInit(void) +{ + if (!(dnsmasqCapsClass = virClassNew("dnsmasqCaps", + sizeof(dnsmasqCaps), + dnsmasqCapsDispose))) { + return -1; + } + + return 0; +} + +VIR_ONCE_GLOBAL_INIT(dnsmasqCaps) + +static void +dnsmasqCapsSet(dnsmasqCapsPtr caps, + dnsmasqCapsFlags flag) +{ + ignore_value(virBitmapSetBit(caps->flags, flag)); +} + + +#define DNSMASQ_VERSION_STR "Dnsmasq version " + +static int +dnsmasqCapsSetFromBuffer(dnsmasqCapsPtr caps, const char *buf) +{ + const char *p; + + caps->noRefresh = true; + + p = STRSKIP(buf, DNSMASQ_VERSION_STR); + if (!p) + goto fail; + virSkipSpaces(&p); + if (virParseVersionString(p, &caps->version, true) < 0) + goto fail; + + if (strstr(buf, "--bind-dynamic")) + dnsmasqCapsSet(caps, DNSMASQ_CAPS_BIND_DYNAMIC); + + VIR_INFO("dnsmasq version is %d.%d, --bind-dynamic is %s", + (int)caps->version / 1000000, (int)(caps->version % 1000000) / 1000, + dnsmasqCapsGet(caps, DNSMASQ_CAPS_BIND_DYNAMIC) + ? "present" : "NOT present"); + return 0; + +fail: + p = strchrnul(buf, '\n'); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot parse %s version number in '%.*s'"), + caps->binaryPath, (int) (p - buf), buf); + return -1; + +} + +static int +dnsmasqCapsSetFromFile(dnsmasqCapsPtr caps, const char *path) +{ + int ret = -1; + char *buf = NULL; + + if (virFileReadAll(path, 1024 * 1024, &buf) < 0) + goto cleanup; + + ret = dnsmasqCapsSetFromBuffer(caps, buf); + +cleanup: + VIR_FREE(buf); + return ret; +} + +static int +dnsmasqCapsRefreshInternal(dnsmasqCapsPtr caps, bool force) +{ + int ret = -1; + struct stat sb; + virCommandPtr cmd = NULL; + char *help = NULL, *version = NULL, *complete = NULL; + + if (!caps || caps->noRefresh) + return 0; + + if (stat(caps->binaryPath, &sb) < 0) { + virReportSystemError(errno, _("Cannot check dnsmasq binary %s"), + caps->binaryPath); + return -1; + } + if (!force && caps->mtime == sb.st_mtime) { + return 0; + } + caps->mtime = sb.st_mtime; + + /* Make sure the binary we are about to try exec'ing exists. + * Technically we could catch the exec() failure, but that's + * in a sub-process so it's hard to feed back a useful error. + */ + if (!virFileIsExecutable(caps->binaryPath)) { + virReportSystemError(errno, _("dnsmasq binary %s is not executable"), + caps->binaryPath); + goto cleanup; + } + + cmd = virCommandNewArgList(caps->binaryPath, "--version", NULL); + virCommandSetOutputBuffer(cmd, &version); + virCommandAddEnvPassCommon(cmd); + virCommandClearCaps(cmd); + if (virCommandRun(cmd, NULL) < 0) { + virReportSystemError(errno, _("failed to run '%s --version': %s"), + caps->binaryPath, version); + goto cleanup; + } + virCommandFree(cmd); + + cmd = virCommandNewArgList(caps->binaryPath, "--help", NULL); + virCommandSetOutputBuffer(cmd, &help); + virCommandAddEnvPassCommon(cmd); + virCommandClearCaps(cmd); + if (virCommandRun(cmd, NULL) < 0) { + virReportSystemError(errno, _("failed to run '%s --help': %s"), + caps->binaryPath, help); + goto cleanup; + } + + if (virAsprintf(&complete, "%s\n%s", version, help) < 0) { + virReportOOMError(); + goto cleanup; + } + + ret = dnsmasqCapsSetFromBuffer(caps, complete); + +cleanup: + virCommandFree(cmd); + VIR_FREE(help); + VIR_FREE(version); + VIR_FREE(complete); + return ret; +} + +static dnsmasqCapsPtr +dnsmasqCapsNewEmpty(const char *binaryPath) +{ + dnsmasqCapsPtr caps; + + if (dnsmasqCapsInitialize() < 0) + return NULL; + if (!(caps = virObjectNew(dnsmasqCapsClass))) + return NULL; + if (!(caps->flags = virBitmapNew(DNSMASQ_CAPS_LAST))) + goto error; + if (!(caps->binaryPath = strdup(binaryPath ? binaryPath : DNSMASQ))) + goto error; + return caps; + +error: + virReportOOMError(); + virObjectUnref(caps); + return NULL; +} + +dnsmasqCapsPtr +dnsmasqCapsNewFromBuffer(const char *buf, const char *binaryPath) +{ + dnsmasqCapsPtr caps = dnsmasqCapsNewEmpty(binaryPath); + + if (!caps) + return NULL; + + if (dnsmasqCapsSetFromBuffer(caps, buf) < 0) { + virObjectUnref(caps); + return NULL; + } + return caps; +} + +dnsmasqCapsPtr +dnsmasqCapsNewFromFile(const char *dataPath, const char *binaryPath) +{ + dnsmasqCapsPtr caps = dnsmasqCapsNewEmpty(binaryPath); + + if (!caps) + return NULL; + + if (dnsmasqCapsSetFromFile(caps, dataPath) < 0) { + virObjectUnref(caps); + return NULL; + } + return caps; +} + +dnsmasqCapsPtr +dnsmasqCapsNewFromBinary(const char *binaryPath) +{ + dnsmasqCapsPtr caps = dnsmasqCapsNewEmpty(binaryPath); + + if (!caps) + return NULL; + + if (dnsmasqCapsRefreshInternal(caps, true) < 0) { + virObjectUnref(caps); + return NULL; + } + return caps; +} + +/** dnsmasqCapsRefresh: + * + * Refresh an existing caps object if the binary has changed. If + * there isn't yet a caps object (if it's NULL), create a new one. + * + * Returns 0 on success, -1 on failure + */ +int +dnsmasqCapsRefresh(dnsmasqCapsPtr *caps, const char *binaryPath) +{ + if (!*caps) { + *caps = dnsmasqCapsNewFromBinary(binaryPath); + return *caps ? 0 : -1; + } + return dnsmasqCapsRefreshInternal(*caps, false); +} + +const char * +dnsmasqCapsGetBinaryPath(dnsmasqCapsPtr caps) +{ + return caps ? caps->binaryPath : DNSMASQ; +} + +unsigned long +dnsmasqCapsGetVersion(dnsmasqCapsPtr caps) +{ + if (caps) + return caps->version; + else + return 0; +} + +bool +dnsmasqCapsGet(dnsmasqCapsPtr caps, dnsmasqCapsFlags flag) +{ + bool b; + + if (!caps || virBitmapGetBit(caps->flags, flag, &b) < 0) + return false; + else + return b; +} diff --git a/src/util/virdnsmasq.h b/src/util/virdnsmasq.h new file mode 100644 index 0000000..7a39232 --- /dev/null +++ b/src/util/virdnsmasq.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2007-2012 Red Hat, Inc. + * Copyright (C) 2010 Satoru SATOH <satoru.satoh@xxxxxxxxx> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * based on iptables.h + */ + +#ifndef __DNSMASQ_H__ +# define __DNSMASQ_H__ + +# include "virobject.h" +# include "virsocketaddr.h" + +typedef struct +{ + /* + * Each entry holds a string, "<mac_addr>,<hostname>,<ip_addr>" such as + * "01:23:45:67:89:0a,foo,10.0.0.3". + */ + char *host; + +} dnsmasqDhcpHost; + +typedef struct +{ + unsigned int nhosts; + dnsmasqDhcpHost *hosts; + + char *path; /* Absolute path of dnsmasq's hostsfile. */ +} dnsmasqHostsfile; + +typedef struct +{ + unsigned int nhostnames; + char *ip; + char **hostnames; + +} dnsmasqAddnHost; + +typedef struct +{ + unsigned int nhosts; + dnsmasqAddnHost *hosts; + + char *path; /* Absolute path of dnsmasq's hostsfile. */ +} dnsmasqAddnHostsfile; + +typedef struct +{ + char *config_dir; + dnsmasqHostsfile *hostsfile; + dnsmasqAddnHostsfile *addnhostsfile; +} dnsmasqContext; + +typedef enum { + DNSMASQ_CAPS_BIND_DYNAMIC = 0, /* support for --bind-dynamic */ + + DNSMASQ_CAPS_LAST, /* this must always be the last item */ +} dnsmasqCapsFlags; + +typedef struct _dnsmasqCaps dnsmasqCaps; +typedef dnsmasqCaps *dnsmasqCapsPtr; + + +dnsmasqContext * dnsmasqContextNew(const char *network_name, + const char *config_dir); +void dnsmasqContextFree(dnsmasqContext *ctx); +int dnsmasqAddDhcpHost(dnsmasqContext *ctx, + const char *mac, + virSocketAddr *ip, + const char *name, + bool ipv6); +int dnsmasqAddHost(dnsmasqContext *ctx, + virSocketAddr *ip, + const char *name); +int dnsmasqSave(const dnsmasqContext *ctx); +int dnsmasqDelete(const dnsmasqContext *ctx); +int dnsmasqReload(pid_t pid); + +dnsmasqCapsPtr dnsmasqCapsNewFromBuffer(const char *buf, + const char *binaryPath); +dnsmasqCapsPtr dnsmasqCapsNewFromFile(const char *dataPath, + const char *binaryPath); +dnsmasqCapsPtr dnsmasqCapsNewFromBinary(const char *binaryPath); +int dnsmasqCapsRefresh(dnsmasqCapsPtr *caps, const char *binaryPath); +bool dnsmasqCapsGet(dnsmasqCapsPtr caps, dnsmasqCapsFlags flag); +const char *dnsmasqCapsGetBinaryPath(dnsmasqCapsPtr caps); +unsigned long dnsmasqCapsGetVersion(dnsmasqCapsPtr caps); + +# define DNSMASQ_DHCPv6_MAJOR_REQD 2 +# define DNSMASQ_DHCPv6_MINOR_REQD 64 +# define DNSMASQ_RA_MAJOR_REQD 2 +# define DNSMASQ_RA_MINOR_REQD 64 + +# define DNSMASQ_DHCPv6_SUPPORT(CAPS) \ + (dnsmasqCapsGetVersion(CAPS) >= \ + (DNSMASQ_DHCPv6_MAJOR_REQD * 1000000) + \ + (DNSMASQ_DHCPv6_MINOR_REQD * 1000)) +# define DNSMASQ_RA_SUPPORT(CAPS) \ + (dnsmasqCapsGetVersion(CAPS) >= \ + (DNSMASQ_RA_MAJOR_REQD * 1000000) + \ + (DNSMASQ_RA_MINOR_REQD * 1000)) +#endif /* __DNSMASQ_H__ */ -- 1.7.11.7 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list