[libvirt] [PATCH V1 2/3] nwfilter: accept broadcasted DHCP replies in DHCP snooping code
Daniel Veillard
veillard at redhat.com
Fri Aug 31 03:39:50 UTC 2012
On Thu, Aug 30, 2012 at 02:29:50PM -0400, Stefan Berger wrote:
> Some DHCP servers send their DHCP replies to the broadcast MAC address
> rather than to the MAC address of the VM. The existing DHCP snooping
> code assumes that the reply always goes to the MAC address of the VM
> thus filtering the traffic of some DHCP servers' replies.
>
> The below patch adapts the code to
>
> 1) filter DHCP replies by comparing the MAC address in the reply against
> the MAC address of the VM (held in the snoop request)
>
> 2) adapts the pcap filter for traffic towards the VM to accept DHCP replies
> sent to any MAC address; for further filtering we rely on 1)
>
> 3) creates initial rules that are active while waiting for DHCP replies;
> these rules now accept DHCP replies to the VM's MAC address or to the
> MAC broadcast address
>
> ---
> src/nwfilter/nwfilter_dhcpsnoop.c | 36 +++++++++++++++++++++++-------
> src/nwfilter/nwfilter_ebiptables_driver.c | 35 +++++++++++++++++------------
> 2 files changed, 49 insertions(+), 22 deletions(-)
>
> Index: libvirt-acl/src/nwfilter/nwfilter_dhcpsnoop.c
> ===================================================================
> --- libvirt-acl.orig/src/nwfilter/nwfilter_dhcpsnoop.c
> +++ libvirt-acl/src/nwfilter/nwfilter_dhcpsnoop.c
> @@ -1010,6 +1010,17 @@ virNWFilterSnoopDHCPDecode(virNWFilterSn
> if (len < 0)
> return -2; /* invalid packet length */
>
> + /*
> + * some DHCP servers send their responses as MAC broadcast replies
> + * filter messages from the server also by the destination MAC
> + * inside the DHCP response
> + */
> + if (!fromVM) {
> + if (virMacAddrCmpRaw(&req->macaddr,
> + (unsigned char *)&pd->d_chaddr) != 0)
> + return -2;
> + }
> +
> if (virNWFilterSnoopDHCPGetOpt(pd, len, &mtype, &leasetime) < 0)
> return -2;
>
> @@ -1069,7 +1080,6 @@ virNWFilterSnoopDHCPOpen(const char *ifn
> char pcap_errbuf[PCAP_ERRBUF_SIZE];
> char *ext_filter = NULL;
> char macaddr[VIR_MAC_STRING_BUFLEN];
> - const char *ext;
>
> virMacAddrFormat(mac, macaddr);
>
> @@ -1080,14 +1090,24 @@ virNWFilterSnoopDHCPOpen(const char *ifn
> * extend the filter with the macaddr of the VM; filter the
> * more unlikely parameters first, then go for the MAC
> */
> - ext = "and ether src";
> + if (virAsprintf(&ext_filter,
> + "%s and ether src %s", filter, macaddr) < 0) {
> + virReportOOMError();
> + return NULL;
> + }
> } else {
> - ext = "and ether dst";
> - }
> -
> - if (virAsprintf(&ext_filter, "%s %s %s", filter, ext, macaddr) < 0) {
> - virReportOOMError();
> - return NULL;
> + /*
> + * Some DHCP servers respond via MAC broadcast; we rely on later
> + * filtering of responses by comparing the MAC address inside the
> + * DHCP response against the one of the VM. Assuming that the
> + * bridge learns the VM's MAC address quickly this should not
> + * generate much more traffic than if we filtered by VM and
> + * braodcast MAC as well
> + */
> + if (virAsprintf(&ext_filter, "%s", filter) < 0) {
> + virReportOOMError();
> + return NULL;
> + }
> }
>
> handle = pcap_create(ifname, pcap_errbuf);
> Index: libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.c
> ===================================================================
> --- libvirt-acl.orig/src/nwfilter/nwfilter_ebiptables_driver.c
> +++ libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.c
> @@ -3345,6 +3345,7 @@ ebtablesApplyDHCPOnlyRules(const char *i
>
> while (true) {
> char *srcIPParam = NULL;
> + int ctr;
>
> if (idx < num_dhcpsrvrs) {
> const char *dhcpserver;
> @@ -3357,20 +3358,26 @@ ebtablesApplyDHCPOnlyRules(const char *i
> }
> }
>
> - virBufferAsprintf(&buf,
> - CMD_DEF("$EBT -t nat -A %s"
> - " -d %s"
> - " -p ipv4 --ip-protocol udp"
> - " %s"
> - " --ip-sport 67 --ip-dport 68"
> - " -j ACCEPT") CMD_SEPARATOR
> - CMD_EXEC
> - "%s",
> -
> - chain_out,
> - macaddr_str,
> - srcIPParam != NULL ? srcIPParam : "",
> - CMD_STOPONERR(1));
> + /*
> + * create two rules allowing response to MAC address of VM
> + * or to broadcast MAC address
> + */
> + for (ctr = 0; ctr < 2; ctr++) {
> + virBufferAsprintf(&buf,
> + CMD_DEF("$EBT -t nat -A %s"
> + " -d %s"
> + " -p ipv4 --ip-protocol udp"
> + " %s"
> + " --ip-sport 67 --ip-dport 68"
> + " -j ACCEPT") CMD_SEPARATOR
> + CMD_EXEC
> + "%s",
> +
> + chain_out,
> + (ctr == 0) ? macaddr_str : "ff:ff:ff:ff:ff:ff",
> + srcIPParam != NULL ? srcIPParam : "",
> + CMD_STOPONERR(1));
> + }
>
> VIR_FREE(srcIPParam);
>
>
Okay, the only small risk I see is being able to crash early boot of
some vulnerable OSes with broadcast flooding of a nasty guest on that
network. Fairly limited and easy to detect.
Patch looks okay, ACK,
Daniel
--
Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/
daniel at veillard.com | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library http://libvirt.org/
More information about the libvir-list
mailing list