commit ce44728e232a39ff42bf87f5eb102bc76b71241d
Author: Pawel Krzesniak <pawel.krzesniak@gmail.com>
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:
