From 527968d433fb06067faa1a10f1f38878e01a393b Mon Sep 17 00:00:00 2001 From: Maxim Perevedentsev Date: Fri, 1 Jul 2016 14:50:18 +0300 Subject: [PATCH] dnsmasq: disable IPv6 default gateway in RA for isolated networks IPv6 RA always contains an implicit default route via the link-local address of the source of RA. This forces the guest to install a route via isolated network, which may disturb the guest's networking in case of multiple interfaces. More info in 013427e6e733f7a662f4e8a9c11f7dad4cd65e3f. The validity of this route is controlled by "default [route] lifetime" field of RA. If the lifetime is set to 0 seconds, then no route is installed by receiver. dnsmasq 2.67+ supports "ra-param=,," option. We pass "ra-param=*,0,0" (here, RA_interval=0 means default) to disable default gateway in RA for isolated networks. --- src/network/bridge_driver.c | 7 +++++++ src/util/virdnsmasq.c | 8 ++++++-- src/util/virdnsmasq.h | 1 + 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 0221a3820b..50202664e4 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -1047,10 +1047,17 @@ networkDnsmasqConfContents(virNetworkObjPtr network, * requests are forwarded on to the dns server listed in the * host's /etc/resolv.conf (since this could be used as a channel * to build a connection to the outside). + * IPv6 RA always contains an implicit default route + * via the sender's link-local address. The only thing we can do + * is set the lifetime of this route to 0, i.e. disable it. */ if (network->def->forward.type == VIR_NETWORK_FORWARD_NONE) { virBufferAddLit(&configbuf, "dhcp-option=3\n" "no-resolv\n"); + if (dnsmasqCapsGet(caps, DNSMASQ_CAPS_RA_PARAM)) { + /* interface=* (any), interval=0 (default), lifetime=0 (seconds) */ + virBufferAddLit(&configbuf, "ra-param=*,0,0\n"); + } } for (i = 0; i < dns->ntxts; i++) { diff --git a/src/util/virdnsmasq.c b/src/util/virdnsmasq.c index cd986087a9..1b78c1fadc 100644 --- a/src/util/virdnsmasq.c +++ b/src/util/virdnsmasq.c @@ -688,12 +688,16 @@ dnsmasqCapsSetFromBuffer(dnsmasqCapsPtr caps, const char *buf) if (strstr(buf, "--bind-interfaces with SO_BINDTODEVICE")) dnsmasqCapsSet(caps, DNSMASQ_CAPS_BINDTODEVICE); + if (strstr(buf, "--ra-param")) + dnsmasqCapsSet(caps, DNSMASQ_CAPS_RA_PARAM); + VIR_INFO("dnsmasq version is %d.%d, --bind-dynamic is %spresent, " - "SO_BINDTODEVICE is %sin use", + "SO_BINDTODEVICE is %sin use, --ra-param is %spresent", (int)caps->version / 1000000, (int)(caps->version % 1000000) / 1000, dnsmasqCapsGet(caps, DNSMASQ_CAPS_BIND_DYNAMIC) ? "" : "NOT ", - dnsmasqCapsGet(caps, DNSMASQ_CAPS_BINDTODEVICE) ? "" : "NOT "); + dnsmasqCapsGet(caps, DNSMASQ_CAPS_BINDTODEVICE) ? "" : "NOT ", + dnsmasqCapsGet(caps, DNSMASQ_CAPS_RA_PARAM) ? "" : "NOT "); return 0; fail: diff --git a/src/util/virdnsmasq.h b/src/util/virdnsmasq.h index ed560da45d..f47bea3abe 100644 --- a/src/util/virdnsmasq.h +++ b/src/util/virdnsmasq.h @@ -71,6 +71,7 @@ typedef struct typedef enum { DNSMASQ_CAPS_BIND_DYNAMIC = 0, /* support for --bind-dynamic */ DNSMASQ_CAPS_BINDTODEVICE = 1, /* uses SO_BINDTODEVICE for --bind-interfaces */ + DNSMASQ_CAPS_RA_PARAM = 2, /* support for --ra-param */ DNSMASQ_CAPS_LAST, /* this must always be the last item */ } dnsmasqCapsFlags; -- GitLab