commit ce44728e232a39ff42bf87f5eb102bc76b71241d Author: Pawel Krzesniak Date: Tue Jan 11 23:36:19 2011 +0100 bridge_driver: handle DNS over IPv6 * dnsmasq listens on all defined IPv[46] addresses for network * Add ip6tables rules to allow DNS traffic to host --- src/network/bridge_driver.c | 59 ++++++++++++++++++++++++++++++++++-------- 1 files changed, 47 insertions(+), 12 deletions(-) diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 4c64a74..d5524db 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -423,7 +423,7 @@ networkSaveDnsmasqHostsfile(virNetworkIpDefPtr ipdef, return 0; } - +#define FAMILIES_COUNT 2 static int networkBuildDnsmasqArgv(virNetworkObjPtr network, virNetworkIpDefPtr ipdef, @@ -431,7 +431,11 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network, virCommandPtr cmd) { int r, ret = -1; int nbleases = 0; - char *bridgeaddr; + char *bridgeaddr = NULL; + char *ipaddr = NULL; + int ii, jj; + virNetworkIpDefPtr tmpipdef; + int families[FAMILIES_COUNT] = { AF_INET, AF_INET6 }; if (!(bridgeaddr = virSocketFormatAddr(&ipdef->address))) goto cleanup; @@ -468,20 +472,29 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network, /* *no* conf file */ virCommandAddArgList(cmd, "--conf-file=", "", NULL); - /* - * XXX does not actually work, due to some kind of - * race condition setting up ipv6 addresses on the - * interface. A sleep(10) makes it work, but that's - * clearly not practical - * - * virCommandAddArg(cmd, "--interface"); - * virCommandAddArg(cmd, ipdef->bridge); - */ virCommandAddArgList(cmd, - "--listen-address", bridgeaddr, "--except-interface", "lo", NULL); + /* + * --interface does not actually work with dnsmasq < 2.47, + * due to DAD for ipv6 addresses on the interface. + * + * virCommandAddArgList(cmd, "--interface", ipdef->bridge, NULL); + * + * So listen on all defined IPv[46] addresses + */ + for (ii = 0; ii < FAMILIES_COUNT; ii++) { + for (jj = 0; + (tmpipdef = virNetworkDefGetIpByIndex(network->def, families[ii], jj)); + jj++) { + if (!(ipaddr = virSocketFormatAddr(&tmpipdef->address))) + goto cleanup; + virCommandAddArgList(cmd, "--listen-address", ipaddr, NULL); + VIR_FREE(ipaddr); + } + } + for (r = 0 ; r < ipdef->nranges ; r++) { char *saddr = virSocketFormatAddr(&ipdef->ranges[r].start); if (!saddr) @@ -1027,9 +1040,31 @@ networkAddGeneralIp6tablesRules(struct network_driver *driver, goto err3; } + /* allow DNS over IPv6 */ + if (iptablesAddTcpInput(driver->iptables, AF_INET6, + network->def->bridge, 53) < 0) { + networkReportError(VIR_ERR_SYSTEM_ERROR, + _("failed to add ip6tables rule to allow DNS requests from '%s'"), + network->def->bridge); + goto err4; + } + + if (iptablesAddUdpInput(driver->iptables, AF_INET6, + network->def->bridge, 53) < 0) { + networkReportError(VIR_ERR_SYSTEM_ERROR, + _("failed to add ip6tables rule to allow DNS requests from '%s'"), + network->def->bridge); + goto err5; + } + + return 0; /* unwind in reverse order from the point of failure */ +err5: + iptablesRemoveTcpInput(driver->iptables, AF_INET6, network->def->bridge, 53); +err4: + iptablesRemoveForwardAllowCross(driver->iptables, AF_INET6, network->def->bridge); err3: iptablesRemoveForwardRejectIn(driver->iptables, AF_INET6, network->def->bridge); err2: