mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 17:34:18 +03:00
network: allow disabling dnsmasq's DNS server
If you define a libvirt virtual network with one or more IP addresses, it starts up an instance of dnsmasq. It's always been possible to avoid dnsmasq's dhcp server (simply don't include a <dhcp> element), but until now it wasn't possible to avoid having the DNS server listening; even if the network has no <dns> element, it is started using default settings. This patch adds a new attribute to <dns>: enable='yes|no'. For backward compatibility, it defaults to 'yes', but if you don't want a DNS server created for the network, you can simply add: <dns enable='no'/> to the network configuration, and next time the network is started there will be no dns server created (if there is dhcp configuration, dnsmasq will be started with "port=0" which disables the DNS server; if there is no dhcp configuration, dnsmasq won't be started at all).
This commit is contained in:
parent
25e8112d7c
commit
9065cfaa88
@ -885,6 +885,18 @@
|
||||
information for the virtual network's DNS
|
||||
server <span class="since">Since 0.9.3</span>.
|
||||
|
||||
<p>
|
||||
The dns element can have an optional <code>enable</code>
|
||||
attribute <span class="since">Since 2.2.0</span>.
|
||||
If <code>enable</code> is "no", then no DNS server will be
|
||||
setup by libvirt for this network (and any other
|
||||
configuration in <code><dns></code> will be ignored).
|
||||
If <code>enable</code> is "yes" or unspecified (including
|
||||
the complete absence of any <code><dns></code>
|
||||
element) then a DNS server will be setup by libvirt to
|
||||
listen on all IP addresses specified in the network's
|
||||
configuration.
|
||||
</p>
|
||||
<p>
|
||||
The dns element
|
||||
can have an optional <code>forwardPlainNames</code>
|
||||
|
@ -247,6 +247,11 @@
|
||||
and other features in the <dns> element -->
|
||||
<optional>
|
||||
<element name="dns">
|
||||
<optional>
|
||||
<attribute name="enable">
|
||||
<ref name="virYesNo"/>
|
||||
</attribute>
|
||||
</optional>
|
||||
<optional>
|
||||
<attribute name="forwardPlainNames">
|
||||
<ref name="virYesNo"/>
|
||||
|
@ -1335,6 +1335,7 @@ virNetworkDNSDefParseXML(const char *networkName,
|
||||
xmlNodePtr *txtNodes = NULL;
|
||||
xmlNodePtr *fwdNodes = NULL;
|
||||
char *forwardPlainNames = NULL;
|
||||
char *enable = NULL;
|
||||
int nhosts, nsrvs, ntxts, nfwds;
|
||||
size_t i;
|
||||
int ret = -1;
|
||||
@ -1342,6 +1343,18 @@ virNetworkDNSDefParseXML(const char *networkName,
|
||||
|
||||
ctxt->node = node;
|
||||
|
||||
enable = virXPathString("string(./@enable)", ctxt);
|
||||
if (enable) {
|
||||
def->enable = virTristateBoolTypeFromString(enable);
|
||||
if (def->enable <= 0) {
|
||||
virReportError(VIR_ERR_XML_ERROR,
|
||||
_("Invalid dns enable setting '%s' "
|
||||
"in network '%s'"),
|
||||
enable, networkName);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
forwardPlainNames = virXPathString("string(./@forwardPlainNames)", ctxt);
|
||||
if (forwardPlainNames) {
|
||||
def->forwardPlainNames = virTristateBoolTypeFromString(forwardPlainNames);
|
||||
@ -1438,8 +1451,17 @@ virNetworkDNSDefParseXML(const char *networkName,
|
||||
}
|
||||
}
|
||||
|
||||
if (def->enable == VIR_TRISTATE_BOOL_NO &&
|
||||
(nfwds || nhosts || nsrvs || ntxts)) {
|
||||
virReportError(VIR_ERR_XML_ERROR,
|
||||
_("Extra data in disabled network '%s'"),
|
||||
networkName);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
VIR_FREE(enable);
|
||||
VIR_FREE(forwardPlainNames);
|
||||
VIR_FREE(fwdNodes);
|
||||
VIR_FREE(hostNodes);
|
||||
@ -2496,12 +2518,22 @@ virNetworkDNSDefFormat(virBufferPtr buf,
|
||||
{
|
||||
size_t i, j;
|
||||
|
||||
if (!(def->forwardPlainNames || def->nfwds || def->nhosts ||
|
||||
if (!(def->enable || def->forwardPlainNames || def->nfwds || def->nhosts ||
|
||||
def->nsrvs || def->ntxts))
|
||||
return 0;
|
||||
|
||||
virBufferAddLit(buf, "<dns");
|
||||
/* default to "yes", but don't format it in the XML */
|
||||
if (def->enable) {
|
||||
const char *fwd = virTristateBoolTypeToString(def->enable);
|
||||
|
||||
if (!fwd) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Unknown enable type %d in network"),
|
||||
def->enable);
|
||||
return -1;
|
||||
}
|
||||
virBufferAsprintf(buf, " enable='%s'", fwd);
|
||||
}
|
||||
if (def->forwardPlainNames) {
|
||||
const char *fwd = virTristateBoolTypeToString(def->forwardPlainNames);
|
||||
|
||||
@ -2512,10 +2544,10 @@ virNetworkDNSDefFormat(virBufferPtr buf,
|
||||
return -1;
|
||||
}
|
||||
virBufferAsprintf(buf, " forwardPlainNames='%s'", fwd);
|
||||
if (!(def->nfwds || def->nhosts || def->nsrvs || def->ntxts)) {
|
||||
virBufferAddLit(buf, "/>\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (!(def->nfwds || def->nhosts || def->nsrvs || def->ntxts)) {
|
||||
virBufferAddLit(buf, "/>\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
virBufferAddLit(buf, ">\n");
|
||||
|
@ -128,6 +128,7 @@ struct _virNetworkDNSHostDef {
|
||||
typedef struct _virNetworkDNSDef virNetworkDNSDef;
|
||||
typedef virNetworkDNSDef *virNetworkDNSDefPtr;
|
||||
struct _virNetworkDNSDef {
|
||||
int enable; /* enum virTristateBool */
|
||||
int forwardPlainNames; /* enum virTristateBool */
|
||||
size_t ntxts;
|
||||
virNetworkDNSTxtDefPtr txts;
|
||||
|
@ -916,6 +916,7 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
|
||||
int nbleases = 0;
|
||||
size_t i;
|
||||
virNetworkDNSDefPtr dns = &network->def->dns;
|
||||
bool wantDNS = dns->enable != VIR_TRISTATE_BOOL_NO;
|
||||
virNetworkIPDefPtr tmpipdef, ipdef, ipv4def, ipv6def;
|
||||
bool ipv6SLAAC;
|
||||
char *saddr = NULL, *eaddr = NULL;
|
||||
@ -948,7 +949,13 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
|
||||
"strict-order\n",
|
||||
network->def->name);
|
||||
|
||||
if (network->def->dns.forwarders) {
|
||||
/* if dns is disabled, set its listening port to 0, which
|
||||
* tells dnsmasq to not listen
|
||||
*/
|
||||
if (!wantDNS)
|
||||
virBufferAddLit(&configbuf, "port=0\n");
|
||||
|
||||
if (wantDNS && network->def->dns.forwarders) {
|
||||
virBufferAddLit(&configbuf, "no-resolv\n");
|
||||
for (i = 0; i < network->def->dns.nfwds; i++) {
|
||||
virBufferAsprintf(&configbuf, "server=%s\n",
|
||||
@ -968,7 +975,7 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
|
||||
network->def->domain);
|
||||
}
|
||||
|
||||
if (network->def->dns.forwardPlainNames == VIR_TRISTATE_BOOL_NO) {
|
||||
if (wantDNS && network->def->dns.forwardPlainNames == VIR_TRISTATE_BOOL_NO) {
|
||||
virBufferAddLit(&configbuf, "domain-needed\n");
|
||||
/* need to specify local=// whether or not a domain is
|
||||
* specified, unless the config says we should forward "plain"
|
||||
@ -1061,64 +1068,66 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < dns->ntxts; i++) {
|
||||
virBufferAsprintf(&configbuf, "txt-record=%s,%s\n",
|
||||
dns->txts[i].name,
|
||||
dns->txts[i].value);
|
||||
}
|
||||
|
||||
for (i = 0; i < dns->nsrvs; i++) {
|
||||
/* service/protocol are required, and should have been validated
|
||||
* by the parser.
|
||||
*/
|
||||
if (!dns->srvs[i].service) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Missing required 'service' "
|
||||
"attribute in SRV record of network '%s'"),
|
||||
network->def->name);
|
||||
goto cleanup;
|
||||
if (wantDNS) {
|
||||
for (i = 0; i < dns->ntxts; i++) {
|
||||
virBufferAsprintf(&configbuf, "txt-record=%s,%s\n",
|
||||
dns->txts[i].name,
|
||||
dns->txts[i].value);
|
||||
}
|
||||
if (!dns->srvs[i].protocol) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Missing required 'service' "
|
||||
"attribute in SRV record of network '%s'"),
|
||||
network->def->name);
|
||||
goto cleanup;
|
||||
}
|
||||
/* RFC2782 requires that service and protocol be preceded by
|
||||
* an underscore.
|
||||
*/
|
||||
virBufferAsprintf(&configbuf, "srv-host=_%s._%s",
|
||||
dns->srvs[i].service, dns->srvs[i].protocol);
|
||||
|
||||
/* domain is optional - it defaults to the domain of this network */
|
||||
if (dns->srvs[i].domain)
|
||||
virBufferAsprintf(&configbuf, ".%s", dns->srvs[i].domain);
|
||||
|
||||
/* If target is empty or ".", that means "the service is
|
||||
* decidedly not available at this domain" (RFC2782). In that
|
||||
* case, any port, priority, or weight is irrelevant.
|
||||
*/
|
||||
if (dns->srvs[i].target && STRNEQ(dns->srvs[i].target, ".")) {
|
||||
|
||||
virBufferAsprintf(&configbuf, ",%s", dns->srvs[i].target);
|
||||
/* port, priority, and weight are optional, but are
|
||||
* identified by their position in the line. If an item is
|
||||
* unspecified, but something later in the line *is*
|
||||
* specified, we need to give the default value for the
|
||||
* unspecified item. (According to the dnsmasq manpage,
|
||||
* the default for port is 1).
|
||||
for (i = 0; i < dns->nsrvs; i++) {
|
||||
/* service/protocol are required, and should have been validated
|
||||
* by the parser.
|
||||
*/
|
||||
if (dns->srvs[i].port ||
|
||||
dns->srvs[i].priority || dns->srvs[i].weight)
|
||||
virBufferAsprintf(&configbuf, ",%d",
|
||||
dns->srvs[i].port ? dns->srvs[i].port : 1);
|
||||
if (dns->srvs[i].priority || dns->srvs[i].weight)
|
||||
virBufferAsprintf(&configbuf, ",%d", dns->srvs[i].priority);
|
||||
if (dns->srvs[i].weight)
|
||||
virBufferAsprintf(&configbuf, ",%d", dns->srvs[i].weight);
|
||||
if (!dns->srvs[i].service) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Missing required 'service' "
|
||||
"attribute in SRV record of network '%s'"),
|
||||
network->def->name);
|
||||
goto cleanup;
|
||||
}
|
||||
if (!dns->srvs[i].protocol) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Missing required 'service' "
|
||||
"attribute in SRV record of network '%s'"),
|
||||
network->def->name);
|
||||
goto cleanup;
|
||||
}
|
||||
/* RFC2782 requires that service and protocol be preceded by
|
||||
* an underscore.
|
||||
*/
|
||||
virBufferAsprintf(&configbuf, "srv-host=_%s._%s",
|
||||
dns->srvs[i].service, dns->srvs[i].protocol);
|
||||
|
||||
/* domain is optional - it defaults to the domain of this network */
|
||||
if (dns->srvs[i].domain)
|
||||
virBufferAsprintf(&configbuf, ".%s", dns->srvs[i].domain);
|
||||
|
||||
/* If target is empty or ".", that means "the service is
|
||||
* decidedly not available at this domain" (RFC2782). In that
|
||||
* case, any port, priority, or weight is irrelevant.
|
||||
*/
|
||||
if (dns->srvs[i].target && STRNEQ(dns->srvs[i].target, ".")) {
|
||||
|
||||
virBufferAsprintf(&configbuf, ",%s", dns->srvs[i].target);
|
||||
/* port, priority, and weight are optional, but are
|
||||
* identified by their position in the line. If an item is
|
||||
* unspecified, but something later in the line *is*
|
||||
* specified, we need to give the default value for the
|
||||
* unspecified item. (According to the dnsmasq manpage,
|
||||
* the default for port is 1).
|
||||
*/
|
||||
if (dns->srvs[i].port ||
|
||||
dns->srvs[i].priority || dns->srvs[i].weight)
|
||||
virBufferAsprintf(&configbuf, ",%d",
|
||||
dns->srvs[i].port ? dns->srvs[i].port : 1);
|
||||
if (dns->srvs[i].priority || dns->srvs[i].weight)
|
||||
virBufferAsprintf(&configbuf, ",%d", dns->srvs[i].priority);
|
||||
if (dns->srvs[i].weight)
|
||||
virBufferAsprintf(&configbuf, ",%d", dns->srvs[i].weight);
|
||||
}
|
||||
virBufferAddLit(&configbuf, "\n");
|
||||
}
|
||||
virBufferAddLit(&configbuf, "\n");
|
||||
}
|
||||
|
||||
/* Find the first dhcp for both IPv4 and IPv6 */
|
||||
@ -1198,7 +1207,7 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
|
||||
virBufferAsprintf(&configbuf, "dhcp-range=%s,%s",
|
||||
saddr, eaddr);
|
||||
if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
|
||||
virBufferAsprintf(&configbuf, ",%d", prefix);
|
||||
virBufferAsprintf(&configbuf, ",%d", prefix);
|
||||
virBufferAddLit(&configbuf, "\n");
|
||||
|
||||
VIR_FREE(saddr);
|
||||
@ -1225,7 +1234,7 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
|
||||
virBufferAsprintf(&configbuf, "dhcp-range=%s,static",
|
||||
bridgeaddr);
|
||||
if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
|
||||
virBufferAsprintf(&configbuf, ",%d", prefix);
|
||||
virBufferAsprintf(&configbuf, ",%d", prefix);
|
||||
virBufferAddLit(&configbuf, "\n");
|
||||
VIR_FREE(bridgeaddr);
|
||||
}
|
||||
@ -1278,8 +1287,10 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
|
||||
/* Likewise, always create this file and put it on the
|
||||
* commandline, to allow for runtime additions.
|
||||
*/
|
||||
virBufferAsprintf(&configbuf, "addn-hosts=%s\n",
|
||||
dctx->addnhostsfile->path);
|
||||
if (wantDNS) {
|
||||
virBufferAsprintf(&configbuf, "addn-hosts=%s\n",
|
||||
dctx->addnhostsfile->path);
|
||||
}
|
||||
|
||||
/* Are we doing RA instead of radvd? */
|
||||
if (DNSMASQ_RA_SUPPORT(caps)) {
|
||||
@ -1375,17 +1386,32 @@ static int
|
||||
networkStartDhcpDaemon(virNetworkDriverStatePtr driver,
|
||||
virNetworkObjPtr network)
|
||||
{
|
||||
virNetworkIPDefPtr ipdef;
|
||||
size_t i;
|
||||
bool needDnsmasq = false;
|
||||
virCommandPtr cmd = NULL;
|
||||
char *pidfile = NULL;
|
||||
int ret = -1;
|
||||
dnsmasqContext *dctx = NULL;
|
||||
|
||||
if (!virNetworkDefGetIPByIndex(network->def, AF_UNSPEC, 0)) {
|
||||
if (!(ipdef = virNetworkDefGetIPByIndex(network->def, AF_UNSPEC, 0))) {
|
||||
/* no IP addresses, so we don't need to run */
|
||||
ret = 0;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* see if there are any IP addresses that need a dhcp server */
|
||||
for (i = 0; ipdef && !needDnsmasq;
|
||||
ipdef = virNetworkDefGetIPByIndex(network->def, AF_UNSPEC, i + 1)) {
|
||||
if (ipdef->nranges || ipdef->nhosts)
|
||||
needDnsmasq = true;
|
||||
}
|
||||
|
||||
if (!needDnsmasq && network->def->dns.enable == VIR_TRISTATE_BOOL_NO) {
|
||||
ret = 0;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (virFileMakePath(driver->pidDir) < 0) {
|
||||
virReportSystemError(errno,
|
||||
_("cannot create directory %s"),
|
||||
|
11
tests/networkxml2confdata/routed-network-no-dns.conf
Normal file
11
tests/networkxml2confdata/routed-network-no-dns.conf
Normal file
@ -0,0 +1,11 @@
|
||||
##WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
|
||||
##OVERWRITTEN AND LOST. Changes to this configuration should be made using:
|
||||
## virsh net-edit local
|
||||
## or other application using the libvirt API.
|
||||
##
|
||||
## dnsmasq conf file created by libvirt
|
||||
strict-order
|
||||
port=0
|
||||
except-interface=lo
|
||||
bind-dynamic
|
||||
interface=virbr1
|
10
tests/networkxml2confdata/routed-network-no-dns.xml
Normal file
10
tests/networkxml2confdata/routed-network-no-dns.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<network>
|
||||
<name>local</name>
|
||||
<uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
|
||||
<bridge name="virbr1"/>
|
||||
<mac address='12:34:56:78:9A:BC'/>
|
||||
<forward mode="route" dev="eth1"/>
|
||||
<dns enable='no'/>
|
||||
<ip address="192.168.122.1" netmask="255.255.255.0">
|
||||
</ip>
|
||||
</network>
|
@ -117,6 +117,7 @@ mymain(void)
|
||||
DO_TEST("nat-network-dns-srv-record-minimal", restricted);
|
||||
DO_TEST("nat-network-name-with-quotes", restricted);
|
||||
DO_TEST("routed-network", full);
|
||||
DO_TEST("routed-network-no-dns", full);
|
||||
DO_TEST("open-network", full);
|
||||
DO_TEST("nat-network", dhcpv6);
|
||||
DO_TEST("nat-network-dns-txt-record", full);
|
||||
|
@ -0,0 +1,12 @@
|
||||
<network>
|
||||
<name>local</name>
|
||||
<uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
|
||||
<bridge name="virbr1"/>
|
||||
<mac address='12:34:56:78:9A:BC'/>
|
||||
<forward mode="route" dev="eth1"/>
|
||||
<dns enable='no'>
|
||||
<txt name='example' value='example value'/>
|
||||
</dns>
|
||||
<ip address="192.168.122.1" netmask="255.255.255.0">
|
||||
</ip>
|
||||
</network>
|
10
tests/networkxml2xmlin/routed-network-no-dns.xml
Normal file
10
tests/networkxml2xmlin/routed-network-no-dns.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<network>
|
||||
<name>local</name>
|
||||
<uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
|
||||
<bridge name="virbr1"/>
|
||||
<mac address='12:34:56:78:9A:BC'/>
|
||||
<forward mode="route" dev="eth1"/>
|
||||
<dns enable='no'/>
|
||||
<ip address="192.168.122.1" netmask="255.255.255.0">
|
||||
</ip>
|
||||
</network>
|
12
tests/networkxml2xmlout/routed-network-no-dns.xml
Normal file
12
tests/networkxml2xmlout/routed-network-no-dns.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<network>
|
||||
<name>local</name>
|
||||
<uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
|
||||
<forward dev='eth1' mode='route'>
|
||||
<interface dev='eth1'/>
|
||||
</forward>
|
||||
<bridge name='virbr1' stp='on' delay='0'/>
|
||||
<mac address='12:34:56:78:9a:bc'/>
|
||||
<dns enable='no'/>
|
||||
<ip address='192.168.122.1' netmask='255.255.255.0'>
|
||||
</ip>
|
||||
</network>
|
@ -127,6 +127,8 @@ mymain(void)
|
||||
DO_TEST("empty-allow-ipv6");
|
||||
DO_TEST("isolated-network");
|
||||
DO_TEST("routed-network");
|
||||
DO_TEST("routed-network-no-dns");
|
||||
DO_TEST_PARSE_ERROR("routed-network-no-dns-extra-elements");
|
||||
DO_TEST("open-network");
|
||||
DO_TEST_PARSE_ERROR("open-network-with-forward-dev");
|
||||
DO_TEST("nat-network");
|
||||
|
Loading…
Reference in New Issue
Block a user