[libvirt] [PATCH 3/9] add DHCP snooping support to nwfilter

David L Stevens dlstevens at us.ibm.com
Mon May 9 20:02:55 UTC 2011


This patch changes rules of the form:

	if ! addr drop
        accept
to:
	if addr return
	...
	drop

The patch adds a "mac" chain to do a mac address list and separates the "arp"
chain into separate "arpmac" and "arpip" chains that can check multiple MAC
or IP addresses in any combination. This patch itself does not support multiple
addresses via the MAC and IP variables, but only changes the form of the rules
to allow multiple addresses in the future.

Signed-off-by: David L Stevens <dlstevens at us.ibm.com>

diff --git a/examples/xml/nwfilter/Makefile.am b/examples/xml/nwfilter/Makefile.am
index 439e7b8..8ef9a71 100644
--- a/examples/xml/nwfilter/Makefile.am
+++ b/examples/xml/nwfilter/Makefile.am
@@ -7,6 +7,8 @@ FILTERS = \
 	allow-ipv4.xml \
 	clean-traffic.xml \
 	no-arp-spoofing.xml \
+	no-arpmac-spoofing.xml \
+	no-arpip-spoofing.xml \
 	no-ip-multicast.xml \
 	no-ip-spoofing.xml \
 	no-mac-broadcast.xml \
diff --git a/examples/xml/nwfilter/allow-arp.xml b/examples/xml/nwfilter/allow-arp.xml
index 63a92b2..006bb54 100644
--- a/examples/xml/nwfilter/allow-arp.xml
+++ b/examples/xml/nwfilter/allow-arp.xml
@@ -1,3 +1,6 @@
-<filter name='allow-arp' chain='arp'>
+<filter name='allow-arp' chain='arpmac'>
+  <rule direction='inout' action='accept'/>
+</filter>
+<filter name='allow-arp' chain='arpip'>
   <rule direction='inout' action='accept'/>
 </filter>
diff --git a/examples/xml/nwfilter/clean-traffic.xml b/examples/xml/nwfilter/clean-traffic.xml
index 40f0ecb..9cee799 100644
--- a/examples/xml/nwfilter/clean-traffic.xml
+++ b/examples/xml/nwfilter/clean-traffic.xml
@@ -11,10 +11,10 @@
    <!-- preventing ARP spoofing/poisoning -->
    <filterref filter='no-arp-spoofing'/>
 
-   <!-- preventing any other traffic than IPv4 and ARP -->
-   <filterref filter='no-other-l2-traffic'/>
-
    <!-- allow qemu to send a self-announce upon migration end -->
    <filterref filter='qemu-announce-self'/>
 
+   <!-- preventing any other traffic than IPv4 and ARP -->
+   <filterref filter='no-other-l2-traffic'/>
+
 </filter>
diff --git a/examples/xml/nwfilter/no-arp-spoofing.xml b/examples/xml/nwfilter/no-arp-spoofing.xml
index fdd4e60..1979b20 100644
--- a/examples/xml/nwfilter/no-arp-spoofing.xml
+++ b/examples/xml/nwfilter/no-arp-spoofing.xml
@@ -1,17 +1,4 @@
-<filter name='no-arp-spoofing' chain='arp'>
-   <uuid>f88f1932-debf-4aa1-9fbe-f10d3aa4bc95</uuid>
-   <rule action='drop' direction='out' priority='300' >
-       <mac match='no' srcmacaddr='$MAC'/>
-   </rule>
-
-   <!-- no arp spoofing -->
-   <!-- drop if ipaddr or macaddr does not belong to guest -->
-   <rule action='drop' direction='out' priority='350' >
-       <arp match='no' arpsrcmacaddr='$MAC'/>
-   </rule>
-   <rule action='drop' direction='out' priority='400' >
-       <arp match='no' arpsrcipaddr='$IP' />
-   </rule>
-   <!-- drop everything else -->
-   <rule action='drop' direction='out' priority='1000' />
+<filter name='no-arp-spoofing'>
+   <filterref filter='no-arpmac-spoofing' />
+   <filterref filter='no-arpip-spoofing' />
 </filter>
diff --git a/examples/xml/nwfilter/no-arpip-spoofing.xml b/examples/xml/nwfilter/no-arpip-spoofing.xml
new file mode 100644
index 0000000..ee42d40
--- /dev/null
+++ b/examples/xml/nwfilter/no-arpip-spoofing.xml
@@ -0,0 +1,12 @@
+<filter name='no-arpip-spoofing' chain='arpip'>
+   <!-- no arp spoofing -->
+   <!-- drop if ipaddr does not belong to guest -->
+   <rule action='return' direction='out' priority='400' >
+       <arp match='yes' arpsrcipaddr='$IP' />
+   </rule>
+   <rule action='return' direction='out' priority='410' >
+       <arp match='yes' arpsrcipaddr='0.0.0.0' />
+   </rule>
+   <!-- drop everything else -->
+   <rule action='drop' direction='out' priority='1000' />
+</filter>
diff --git a/examples/xml/nwfilter/no-arpmac-spoofing.xml b/examples/xml/nwfilter/no-arpmac-spoofing.xml
new file mode 100644
index 0000000..90499d3
--- /dev/null
+++ b/examples/xml/nwfilter/no-arpmac-spoofing.xml
@@ -0,0 +1,7 @@
+<filter name='no-arpmac-spoofing' chain='arpmac'>
+   <rule action='return' direction='out' priority='350' >
+       <arp match='yes' arpsrcmacaddr='$MAC'/>
+   </rule>
+   <!-- drop everything else -->
+   <rule action='drop' direction='out' priority='1000' />
+</filter>
diff --git a/examples/xml/nwfilter/no-ip-spoofing.xml b/examples/xml/nwfilter/no-ip-spoofing.xml
index b8c94c8..84e8a5e 100644
--- a/examples/xml/nwfilter/no-ip-spoofing.xml
+++ b/examples/xml/nwfilter/no-ip-spoofing.xml
@@ -1,7 +1,9 @@
 <filter name='no-ip-spoofing' chain='ipv4'>
 
     <!-- drop if srcipaddr is not the IP address of the guest -->
-    <rule action='drop' direction='out'>
-        <ip match='no' srcipaddr='$IP' />
+    <rule action='return' direction='out'>
+        <ip match='yes' srcipaddr='$IP' />
     </rule>
+    <!-- drop any that don't match the source IP list -->
+    <rule action='drop' direction='out' />
 </filter>
diff --git a/examples/xml/nwfilter/no-mac-spoofing.xml b/examples/xml/nwfilter/no-mac-spoofing.xml
index f210623..aee56c7 100644
--- a/examples/xml/nwfilter/no-mac-spoofing.xml
+++ b/examples/xml/nwfilter/no-mac-spoofing.xml
@@ -1,5 +1,9 @@
-<filter name='no-mac-spoofing' chain='ipv4'>
-  <rule action='drop' direction='out' priority='10'>
-      <mac match='no' srcmacaddr='$MAC' />
-  </rule>
+<filter name='no-mac-spoofing' chain='mac'>
+   <!-- no mac spoofing -->
+   <!-- drop if macaddr does not belong to guest -->
+   <rule action='return' direction='out' priority='350' >
+       <mac match='yes' srcmacaddr='$MAC'/>
+   </rule>
+   <!-- drop everything else -->
+   <rule action='drop' direction='out' priority='1000' />
 </filter>
diff --git a/examples/xml/nwfilter/no-other-l2-traffic.xml b/examples/xml/nwfilter/no-other-l2-traffic.xml
index 8bad86e..0501b1a 100644
--- a/examples/xml/nwfilter/no-other-l2-traffic.xml
+++ b/examples/xml/nwfilter/no-other-l2-traffic.xml
@@ -1,7 +1,12 @@
-<filter name='no-other-l2-traffic'>
+<filter name='no-other-l2-traffic' chain='root'>
 
-    <!-- drop all other l2 traffic than for which rules have been
-         written for; i.e., drop all other than arp and ipv4 traffic -->
-    <rule action='drop' direction='inout' priority='1000'/>
+    <!-- drop all other than arp and ipv4 traffic -->
+    <rule action='accept' direction='inout'>
+        <mac protocolid='0x800' />
+    </rule>
+    <rule action='accept' direction='inout'>
+        <mac protocolid='0x806' />
+    </rule>
+    <rule action='drop' direction='inout' priority='1000' />
 
 </filter>
diff --git a/src/conf/nwfilter_conf.c b/src/conf/nwfilter_conf.c
index c5705c1..df1a012 100644
--- a/src/conf/nwfilter_conf.c
+++ b/src/conf/nwfilter_conf.c
@@ -82,7 +82,9 @@ VIR_ENUM_IMPL(virNWFilterEbtablesTable, VIR_NWFILTER_EBTABLES_TABLE_LAST,
 
 VIR_ENUM_IMPL(virNWFilterChainSuffix, VIR_NWFILTER_CHAINSUFFIX_LAST,
               "root",
-              "arp",
+              "mac",
+              "arpmac",
+              "arpip",
               "rarp",
               "ipv4",
               "ipv6");
diff --git a/src/conf/nwfilter_conf.h b/src/conf/nwfilter_conf.h
index ef60b6b..4d60751 100644
--- a/src/conf/nwfilter_conf.h
+++ b/src/conf/nwfilter_conf.h
@@ -425,7 +425,9 @@ struct _virNWFilterEntry {
 
 enum virNWFilterChainSuffixType {
     VIR_NWFILTER_CHAINSUFFIX_ROOT = 0,
-    VIR_NWFILTER_CHAINSUFFIX_ARP,
+    VIR_NWFILTER_CHAINSUFFIX_MAC,
+    VIR_NWFILTER_CHAINSUFFIX_ARPMAC,
+    VIR_NWFILTER_CHAINSUFFIX_ARPIP,
     VIR_NWFILTER_CHAINSUFFIX_RARP,
     VIR_NWFILTER_CHAINSUFFIX_IPv4,
     VIR_NWFILTER_CHAINSUFFIX_IPv6,
diff --git a/src/nwfilter/nwfilter_ebiptables_driver.c b/src/nwfilter/nwfilter_ebiptables_driver.c
index 39bd4a5..fa6f719 100644
--- a/src/nwfilter/nwfilter_ebiptables_driver.c
+++ b/src/nwfilter/nwfilter_ebiptables_driver.c
@@ -129,20 +129,24 @@ struct ushort_map {
 
 
 enum l3_proto_idx {
-    L3_PROTO_IPV4_IDX = 0,
-    L3_PROTO_IPV6_IDX,
-    L3_PROTO_ARP_IDX,
+    L3_PROTO_MAC_IDX = 0,
+    L3_PROTO_ARPMAC_IDX,
+    L3_PROTO_ARPIP_IDX,
     L3_PROTO_RARP_IDX,
+    L3_PROTO_IPV4_IDX,
+    L3_PROTO_IPV6_IDX,
     L3_PROTO_LAST_IDX
 };
 
 #define USHORTMAP_ENTRY_IDX(IDX, ATT, VAL) [IDX] = { .attr = ATT, .val = VAL }
 
 static const struct ushort_map l3_protocols[] = {
-    USHORTMAP_ENTRY_IDX(L3_PROTO_IPV4_IDX, ETHERTYPE_IP    , "ipv4"),
-    USHORTMAP_ENTRY_IDX(L3_PROTO_IPV6_IDX, ETHERTYPE_IPV6  , "ipv6"),
-    USHORTMAP_ENTRY_IDX(L3_PROTO_ARP_IDX , ETHERTYPE_ARP   , "arp"),
-    USHORTMAP_ENTRY_IDX(L3_PROTO_RARP_IDX, ETHERTYPE_REVARP, "rarp"),
+    USHORTMAP_ENTRY_IDX(L3_PROTO_MAC_IDX,   0               , "mac"),
+    USHORTMAP_ENTRY_IDX(L3_PROTO_IPV4_IDX,  ETHERTYPE_IP    , "ipv4"),
+    USHORTMAP_ENTRY_IDX(L3_PROTO_IPV6_IDX,  ETHERTYPE_IPV6  , "ipv6"),
+    USHORTMAP_ENTRY_IDX(L3_PROTO_ARPMAC_IDX,ETHERTYPE_ARP   , "arpmac"),
+    USHORTMAP_ENTRY_IDX(L3_PROTO_ARPIP_IDX, ETHERTYPE_ARP   , "arpip"),
+    USHORTMAP_ENTRY_IDX(L3_PROTO_RARP_IDX,  ETHERTYPE_REVARP, "rarp"),
     USHORTMAP_ENTRY_IDX(L3_PROTO_LAST_IDX, 0               , NULL),
 };
 
@@ -1946,7 +1950,7 @@ ebtablesCreateRuleInstance(char chainPrefix,
 
         virBufferVSprintf(&buf, " -p 0x%x",
                           (rule->prtclType == VIR_NWFILTER_RULE_PROTOCOL_ARP)
-                           ? l3_protocols[L3_PROTO_ARP_IDX].attr
+                           ? l3_protocols[L3_PROTO_ARPMAC_IDX].attr
                            : l3_protocols[L3_PROTO_RARP_IDX].attr);
 
         if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataHWType)) {
@@ -2767,15 +2771,22 @@ ebtablesCreateTmpSubChain(virBufferPtr buf,
     char rootchain[MAX_CHAINNAME_LENGTH], chain[MAX_CHAINNAME_LENGTH];
     char chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
                                   : CHAINPREFIX_HOST_OUT_TEMP;
+    char protostr[16];
 
     PRINT_ROOT_CHAIN(rootchain, chainPrefix, ifname);
     PRINT_CHAIN(chain, chainPrefix, ifname, l3_protocols[protoidx].val);
 
+    if (l3_protocols[protoidx].attr)
+        snprintf(protostr, sizeof(protostr), "-p 0x%04x ",
+                 l3_protocols[protoidx].attr);
+    else
+        protostr[0] = '\0';
+
     virBufferVSprintf(buf,
                       CMD_DEF("%s -t %s -N %s") CMD_SEPARATOR
                       CMD_EXEC
                       "%s"
-                      CMD_DEF("%s -t %s -A %s -p 0x%x -j %s") CMD_SEPARATOR
+                      CMD_DEF("%s -t %s -A %s %s -j %s") CMD_SEPARATOR
                       CMD_EXEC
                       "%s",
 
@@ -2784,7 +2795,7 @@ ebtablesCreateTmpSubChain(virBufferPtr buf,
                       CMD_STOPONERR(stopOnError),
 
                       ebtables_cmd_path, EBTABLES_DEFAULT_TABLE,
-                      rootchain, l3_protocols[protoidx].attr, chain,
+                      rootchain, protostr, chain,
 
                       CMD_STOPONERR(stopOnError));
 
@@ -3357,6 +3368,11 @@ ebiptablesApplyNewRules(virConnectPtr conn ATTRIBUTE_UNUSED,
     if (chains_out != 0)
         ebtablesCreateTmpRootChain(&buf, 0, ifname, 1);
 
+    if (chains_in  & (1 << VIR_NWFILTER_CHAINSUFFIX_MAC))
+        ebtablesCreateTmpSubChain(&buf, 1, ifname, L3_PROTO_MAC_IDX, 1);
+    if (chains_out & (1 << VIR_NWFILTER_CHAINSUFFIX_MAC))
+        ebtablesCreateTmpSubChain(&buf, 0, ifname, L3_PROTO_MAC_IDX, 1);
+
     if (chains_in  & (1 << VIR_NWFILTER_CHAINSUFFIX_IPv4))
         ebtablesCreateTmpSubChain(&buf, 1, ifname, L3_PROTO_IPV4_IDX, 1);
     if (chains_out & (1 << VIR_NWFILTER_CHAINSUFFIX_IPv4))
@@ -3368,10 +3384,14 @@ ebiptablesApplyNewRules(virConnectPtr conn ATTRIBUTE_UNUSED,
         ebtablesCreateTmpSubChain(&buf, 0, ifname, L3_PROTO_IPV6_IDX, 1);
 
     /* keep arp,rarp as last */
-    if (chains_in  & (1 << VIR_NWFILTER_CHAINSUFFIX_ARP))
-        ebtablesCreateTmpSubChain(&buf, 1, ifname, L3_PROTO_ARP_IDX, 1);
-    if (chains_out & (1 << VIR_NWFILTER_CHAINSUFFIX_ARP))
-        ebtablesCreateTmpSubChain(&buf, 0, ifname, L3_PROTO_ARP_IDX, 1);
+    if (chains_in  & (1 << VIR_NWFILTER_CHAINSUFFIX_ARPMAC))
+        ebtablesCreateTmpSubChain(&buf, 1, ifname, L3_PROTO_ARPMAC_IDX, 1);
+    if (chains_in  & (1 << VIR_NWFILTER_CHAINSUFFIX_ARPIP))
+        ebtablesCreateTmpSubChain(&buf, 1, ifname, L3_PROTO_ARPIP_IDX, 1);
+    if (chains_out & (1 << VIR_NWFILTER_CHAINSUFFIX_ARPMAC))
+        ebtablesCreateTmpSubChain(&buf, 0, ifname, L3_PROTO_ARPMAC_IDX, 1);
+    if (chains_out & (1 << VIR_NWFILTER_CHAINSUFFIX_ARPIP))
+        ebtablesCreateTmpSubChain(&buf, 0, ifname, L3_PROTO_ARPIP_IDX, 1);
     if (chains_in  & (1 << VIR_NWFILTER_CHAINSUFFIX_RARP))
         ebtablesCreateTmpSubChain(&buf, 1, ifname, L3_PROTO_RARP_IDX, 1);
     if (chains_out & (1 << VIR_NWFILTER_CHAINSUFFIX_RARP))





More information about the libvir-list mailing list