diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 7f3eb54f136226080818bcce50663c1f36ff42c7..9740fbd14321540ddbbe8256c863ba77db72073b 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -726,15 +726,17 @@ networkDnsmasqConfContents(virNetworkObjPtr network, * dnsmasq doesn't have bind-dynamic, only allow listening on * private/local IP addresses (see RFC1918/RFC3484/RFC4193) */ - if (!virSocketAddrIsPrivate(&tmpipdef->address)) { + if (!dnsmasqCapsGet(caps, DNSMASQ_CAPS_BINDTODEVICE) && + !virSocketAddrIsPrivate(&tmpipdef->address)) { unsigned long version = dnsmasqCapsGetVersion(caps); virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Publicly routable address %s is prohibited. " "The version of dnsmasq on this host (%d.%d) " - "doesn't support the bind-dynamic option, " - "which is required for safe operation on a " - "publicly routable subnet " + "doesn't support the bind-dynamic option or " + "use SO_BINDTODEVICE on listening sockets, " + "one of which is required for safe operation " + "on a publicly routable subnet " "(see CVE-2012-3411). You must either " "upgrade dnsmasq, or use a private/local " "subnet range for this network " diff --git a/src/util/dnsmasq.c b/src/util/dnsmasq.c index e8eab1e29e7c567cde1e7b8397fc39e362adc189..8d714dc7a99d4f5a7c6f81ff4bed8204e095f5a7 100644 --- a/src/util/dnsmasq.c +++ b/src/util/dnsmasq.c @@ -664,10 +664,20 @@ dnsmasqCapsSetFromBuffer(dnsmasqCapsPtr caps, const char *buf) 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"); + /* if this string is a part of the --version output, dnsmasq + * has been patched to use SO_BINDTODEVICE when listening, + * so that it will only accept requests that arrived on the + * listening interface(s) + */ + if (strstr(buf, "--bind-interfaces with SO_BINDTODEVICE")) + dnsmasqCapsSet(caps, DNSMASQ_CAPS_BINDTODEVICE); + + VIR_INFO("dnsmasq version is %d.%d, --bind-dynamic is %spresent, " + "SO_BINDTODEVICE is %sin use", + (int)caps->version / 1000000, + (int)(caps->version % 1000000) / 1000, + dnsmasqCapsGet(caps, DNSMASQ_CAPS_BIND_DYNAMIC) ? "" : "NOT ", + dnsmasqCapsGet(caps, DNSMASQ_CAPS_BIND_DYNAMIC) ? "" : "NOT "); return 0; fail: diff --git a/src/util/dnsmasq.h b/src/util/dnsmasq.h index 7a39232e53e7376d32317ed20251c2e7b140bee1..b83bc96c9e5f32e054e3097753bba11693a43800 100644 --- a/src/util/dnsmasq.h +++ b/src/util/dnsmasq.h @@ -68,6 +68,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_LAST, /* this must always be the last item */ } dnsmasqCapsFlags;