]> xenbits.xensource.com Git - libvirt.git/commitdiff
nwfilter: Add support for icmpv6 filtering
authorStefan Berger <stefanb@linux.vnet.ibm.com>
Wed, 7 Jan 2015 16:41:49 +0000 (11:41 -0500)
committerStefan Berger <stefanb@linux.vnet.ibm.com>
Wed, 7 Jan 2015 16:41:49 +0000 (11:41 -0500)
Make use of the ebtables functionality to be able to filter certain
parameters of icmpv6 packets. Extend the XML parser for icmpv6 types,
type ranges, codes, and code ranges. Extend the nwfilter documentation,
schema, and test cases.

Being able to filter icmpv6 types and codes helps extending the DHCP
snooper for IPv6 and filtering at least some parameters of IPv6's NDP
(Neighbor Discovery Protocol) packets. However, the filtering will not
be as good as the filtering of ARP packets since we cannot
check on IP addresses in the payload of the NDP packets.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
docs/formatnwfilter.html.in
docs/schemas/nwfilter.rng
src/conf/nwfilter_conf.c
src/conf/nwfilter_conf.h
src/nwfilter/nwfilter_ebiptables_driver.c
tests/nwfilterxml2firewalldata/ipv6-linux.args
tests/nwfilterxml2firewalldata/ipv6.xml
tests/nwfilterxml2xmlin/ipv6-test.xml
tests/nwfilterxml2xmlout/ipv6-test.xml

index 073b852abce2623d564a9d57bfe2a2944f931bd4..4a60e2ea9adf8ea855aa0efd838121092bcb0d0b 100644 (file)
          <td>UINT16</td>
          <td>End of range of valid destination ports; requires <code>protocol</code></td>
        </tr>
+       <tr>
+         <td>type<span class="since">(Since 1.2.12)</span></td>
+         <td>UINT8</td>
+         <td>ICMPv6 type; requires <code>protocol</code> to be set to <code>icmpv6</code></td>
+       </tr>
+       <tr>
+         <td>typeend<span class="since">(Since 1.2.12)</span></td>
+         <td>UINT8</td>
+         <td>ICMPv6 type end of range; requires <code>protocol</code> to be set to <code>icmpv6</code></td>
+       </tr>
+       <tr>
+         <td>code<span class="since">(Since 1.2.12)</span></td>
+         <td>UINT8</td>
+         <td>ICMPv6 code; requires <code>protocol</code> to be set to <code>icmpv6</code></td>
+       </tr>
+       <tr>
+         <td>code<span class="since">(Since 1.2.12)</span></td>
+         <td>UINT8</td>
+         <td>ICMPv6 code end of range; requires <code>protocol</code> to be set to <code>icmpv6</code></td>
+       </tr>
        <tr>
          <td>comment <span class="since">(Since 0.8.5)</span></td>
          <td>STRING</td>
index 2b54fd54a09613e99b909b15df409c0dcb094da9..9df39c0a64a4c492889399b4926349fb03d81b5d 100644 (file)
@@ -90,6 +90,7 @@
                   <ref name="common-ipv6-attributes-p1"/>
                   <ref name="common-port-attributes"/>
                   <ref name="ip-attributes"/>
+                  <ref name="icmp-attribute-ranges"/>
                   <ref name="comment-attribute"/>
                 </element>
               </zeroOrMore>
     </interleave>
   </define>
 
+  <define name="icmp-attribute-ranges">
+    <interleave>
+      <optional>
+        <attribute name="type">
+          <ref name="uint8range"/>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="typeend">
+          <ref name="uint8range"/>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="code">
+          <ref name="uint8range"/>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="codeend">
+          <ref name="uint8range"/>
+        </attribute>
+      </optional>
+    </interleave>
+  </define>
+
   <define name="mac-attributes">
     <interleave>
       <optional>
index 317792eb50a32c5507c25b49231107613e6ccc0d..aed82ad28847d781f8bf4899def86637bad62c60 100644 (file)
@@ -1445,6 +1445,26 @@ static const virXMLAttr2Struct ipv6Attributes[] = {
         .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
         .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.portData.dataDstPortEnd),
     },
+    {
+        .name = "type",
+        .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.dataICMPTypeStart),
+    },
+    {
+        .name = "typeend",
+        .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.dataICMPTypeEnd),
+    },
+    {
+        .name = "code",
+        .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.dataICMPCodeStart),
+    },
+    {
+        .name = "codeend",
+        .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
+        .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.dataICMPCodeEnd),
+    },
     COMMENT_PROP_IPHDR(ipv6HdrFilter),
     {
         .name = NULL,
@@ -2219,6 +2239,12 @@ virNWFilterRuleDefFixup(virNWFilterRuleDefPtr rule)
                       rule->p.ipv6HdrFilter.ipHdr.dataSrcIPAddr);
         COPY_NEG_SIGN(rule->p.ipv6HdrFilter.ipHdr.dataDstIPMask,
                       rule->p.ipv6HdrFilter.ipHdr.dataDstIPAddr);
+        COPY_NEG_SIGN(rule->p.ipv6HdrFilter.dataICMPTypeEnd,
+                      rule->p.ipv6HdrFilter.dataICMPTypeStart);
+        COPY_NEG_SIGN(rule->p.ipv6HdrFilter.dataICMPCodeStart,
+                      rule->p.ipv6HdrFilter.dataICMPTypeStart);
+        COPY_NEG_SIGN(rule->p.ipv6HdrFilter.dataICMPCodeEnd,
+                      rule->p.ipv6HdrFilter.dataICMPTypeStart);
         virNWFilterRuleDefFixupIPSet(&rule->p.ipv6HdrFilter.ipHdr);
     break;
 
index f81df60dc3aea30952ff153bf9b4886308b4182a..6e68ecc8577c46a0079ba58c7120ec66932d0998 100644 (file)
@@ -265,6 +265,10 @@ struct _ipv6HdrFilterDef {
     ethHdrDataDef  ethHdr;
     ipHdrDataDef   ipHdr;
     portDataDef    portData;
+    nwItemDesc     dataICMPTypeStart;
+    nwItemDesc     dataICMPTypeEnd;
+    nwItemDesc     dataICMPCodeStart;
+    nwItemDesc     dataICMPCodeEnd;
 };
 
 
index 377b59bcaa8165a3ab18e12f250286edb4091052..423d069e1b268eb60fc61b44e2b3244bacbeb596 100644 (file)
@@ -1826,6 +1826,7 @@ ebtablesCreateRuleInstance(virFirewallPtr fw,
     bool hasMask = false;
     virFirewallRulePtr fwrule;
     int ret = -1;
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
 
     if (STREQ(chainSuffix,
               virNWFilterChainSuffixTypeToString(
@@ -2342,6 +2343,83 @@ ebtablesCreateRuleInstance(virFirewallPtr fw,
                 virFirewallRuleAddArg(fw, fwrule, number);
             }
         }
+
+        if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.dataICMPTypeStart)  ||
+            HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.dataICMPTypeEnd) ||
+            HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.dataICMPCodeStart) ||
+            HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.dataICMPCodeEnd)) {
+            bool lo = false;
+            char *r;
+
+            virFirewallRuleAddArg(fw, fwrule,
+                                  "--ip6-icmp-type");
+
+            if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.dataICMPTypeStart)) {
+                if (printDataType(vars,
+                                  number, sizeof(number),
+                                  &rule->p.ipv6HdrFilter.dataICMPTypeStart) < 0)
+                    goto cleanup;
+                lo = true;
+            } else {
+                ignore_value(virStrcpyStatic(number, "0"));
+            }
+
+            virBufferStrcat(&buf, number, ":", NULL);
+
+            if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.dataICMPTypeEnd)) {
+                if (printDataType(vars,
+                                  numberalt, sizeof(numberalt),
+                                  &rule->p.ipv6HdrFilter.dataICMPTypeEnd) < 0)
+                    goto cleanup;
+            } else {
+                if (lo)
+                    ignore_value(virStrcpyStatic(numberalt, number));
+                else
+                    ignore_value(virStrcpyStatic(numberalt, "255"));
+            }
+
+            virBufferStrcat(&buf, numberalt, "/", NULL);
+
+            lo = false;
+
+            if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.dataICMPCodeStart)) {
+                if (printDataType(vars,
+                                  number, sizeof(number),
+                                  &rule->p.ipv6HdrFilter.dataICMPCodeStart) < 0)
+                    goto cleanup;
+                lo = true;
+            } else {
+                ignore_value(virStrcpyStatic(number, "0"));
+            }
+
+            virBufferStrcat(&buf, number, ":", NULL);
+
+            if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.dataICMPCodeEnd)) {
+                if (printDataType(vars,
+                                  numberalt, sizeof(numberalt),
+                                  &rule->p.ipv6HdrFilter.dataICMPCodeEnd) < 0)
+                    goto cleanup;
+            } else {
+                if (lo)
+                    ignore_value(virStrcpyStatic(numberalt, number));
+                else
+                    ignore_value(virStrcpyStatic(numberalt, "255"));
+            }
+
+            virBufferStrcat(&buf, numberalt, NULL);
+
+            if (ENTRY_WANT_NEG_SIGN(&rule->p.ipv6HdrFilter.dataICMPTypeStart))
+                virFirewallRuleAddArg(fw, fwrule, "!");
+
+            if (virBufferCheckError(&buf) < 0)
+                 goto cleanup;
+
+            r = virBufferContentAndReset(&buf);
+
+            virFirewallRuleAddArg(fw, fwrule, r);
+
+            VIR_FREE(r);
+        }
         break;
 
     case VIR_NWFILTER_RULE_PROTOCOL_NONE:
@@ -2376,6 +2454,8 @@ ebtablesCreateRuleInstance(virFirewallPtr fw,
 
     ret = 0;
  cleanup:
+    virBufferFreeAndReset(&buf);
+
     return ret;
 }
 
index a42566ca702e6d7ce9244fbef088fb47937b9833..735f663716e152e7d3b18353155448a56487d77d 100644 (file)
@@ -18,3 +18,19 @@ ebtables -t nat -A libvirt-J-vnet0 -p ipv6 --ip6-destination 1::2/128 \
 --ip6-source a:b:c::/65 --ip6-protocol 18 -j ACCEPT
 ebtables -t nat -A libvirt-P-vnet0 -p ipv6 --ip6-source 1::2/128 \
 --ip6-destination a:b:c::/65 --ip6-protocol 18 -j ACCEPT
+ebtables -t nat -A libvirt-J-vnet0 -p ipv6 --ip6-destination 1::2/128 \
+--ip6-source a:b:c::/65 --ip6-protocol 58 --ip6-icmp-type 1:11/10:11 -j ACCEPT
+ebtables -t nat -A libvirt-P-vnet0 -p ipv6 --ip6-source 1::2/128 \
+--ip6-destination a:b:c::/65 --ip6-protocol 58 --ip6-icmp-type 1:11/10:11 -j ACCEPT
+ebtables -t nat -A libvirt-J-vnet0 -p ipv6 --ip6-destination 1::2/128 \
+--ip6-source a:b:c::/65 --ip6-protocol 58 --ip6-icmp-type 1:1/10:10 -j ACCEPT
+ebtables -t nat -A libvirt-P-vnet0 -p ipv6 --ip6-source 1::2/128 \
+--ip6-destination a:b:c::/65 --ip6-protocol 58 --ip6-icmp-type 1:1/10:10 -j ACCEPT
+ebtables -t nat -A libvirt-J-vnet0 -p ipv6 --ip6-destination 1::2/128 \
+--ip6-source a:b:c::/65 --ip6-protocol 58 --ip6-icmp-type 0:255/10:10 -j ACCEPT
+ebtables -t nat -A libvirt-P-vnet0 -p ipv6 --ip6-source 1::2/128 \
+--ip6-destination a:b:c::/65 --ip6-protocol 58 --ip6-icmp-type 0:255/10:10 -j ACCEPT
+ebtables -t nat -A libvirt-J-vnet0 -p ipv6 --ip6-destination 1::2/128 \
+--ip6-source a:b:c::/65 --ip6-protocol 58 --ip6-icmp-type 1:1/0:255 -j ACCEPT
+ebtables -t nat -A libvirt-P-vnet0 -p ipv6 --ip6-source 1::2/128 \
+--ip6-destination a:b:c::/65 --ip6-protocol 58 --ip6-icmp-type 1:1/0:255 -j ACCEPT
index 9f67bea737d82f70192fd4ce6ca6ce79dc2c591f..2400958030de1f989ca495e4b9bc7a282594b1db 100644 (file)
       />
   </rule>
 
+  <rule action='accept' direction='inout'>
+     <ipv6 srcipaddr='1::2' srcipmask='128'
+           dstipaddr='a:b:c::'
+           dstipmask='ffff:ffff:ffff:ffff:8000::'
+           protocol='icmpv6'
+           type='1' typeend='11'
+           code='10' codeend='11'
+      />
+  </rule>
+
+  <rule action='accept' direction='inout'>
+     <ipv6 srcipaddr='1::2' srcipmask='128'
+           dstipaddr='a:b:c::'
+           dstipmask='ffff:ffff:ffff:ffff:8000::'
+           protocol='icmpv6'
+           type='1'
+           code='10'
+      />
+  </rule>
+
+  <rule action='accept' direction='inout'>
+     <ipv6 srcipaddr='1::2' srcipmask='128'
+           dstipaddr='a:b:c::'
+           dstipmask='ffff:ffff:ffff:ffff:8000::'
+           protocol='icmpv6'
+           code='10'
+      />
+  </rule>
+
+  <rule action='accept' direction='inout'>
+     <ipv6 srcipaddr='1::2' srcipmask='128'
+           dstipaddr='a:b:c::'
+           dstipmask='ffff:ffff:ffff:ffff:8000::'
+           protocol='icmpv6'
+           type='1'
+      />
+  </rule>
+
 </filter>
index 556796fa0110333d41bcdc3ceda057ab5246e262..2daa3b96ddb270d4fb33c748d3e5d672f0b359f8 100644 (file)
       />
   </rule>
 
+  <rule action='accept' direction='inout'>
+     <ipv6 srcipaddr='1::2' srcipmask='128'
+           dstipaddr='a:b:c::'
+           dstipmask='ffff:ffff:ffff:ffff:8000::'
+           protocol='icmpv6'
+           type='1' typeend='11'
+           code='10' codeend='11'
+      />
+  </rule>
+
+  <rule action='accept' direction='inout'>
+     <ipv6 srcipaddr='1::2' srcipmask='128'
+           dstipaddr='a:b:c::'
+           dstipmask='ffff:ffff:ffff:ffff:8000::'
+           protocol='icmpv6'
+           type='1'
+           code='10'
+      />
+  </rule>
+
+  <rule action='accept' direction='inout'>
+     <ipv6 srcipaddr='1::2' srcipmask='128'
+           dstipaddr='a:b:c::'
+           dstipmask='ffff:ffff:ffff:ffff:8000::'
+           protocol='icmpv6'
+           code='10'
+      />
+  </rule>
+
+  <rule action='accept' direction='inout'>
+     <ipv6 srcipaddr='1::2' srcipmask='128'
+           dstipaddr='a:b:c::'
+           dstipmask='ffff:ffff:ffff:ffff:8000::'
+           protocol='icmpv6'
+           type='1'
+      />
+  </rule>
+
 </filter>
index fcc5c0da2684e817010615a963976c2d10d42a0e..ce9dd062338cae6d121db065b2a0beb588f79cf8 100644 (file)
   <rule action='accept' direction='inout' priority='500'>
     <ipv6 srcipaddr='1::2' srcipmask='128' dstipaddr='a:b:c::' dstipmask='65' protocol='18'/>
   </rule>
+  <rule action='accept' direction='inout'>
+     <ipv6 srcipaddr='1::2' srcipmask='128' dstipaddr='a:b:c::' dstipmask='65' protocol='icmpv6' type='1' typeend='11' code='10' codeend='11'/>
+  </rule>
+  <rule action='accept' direction='inout'>
+     <ipv6 srcipaddr='1::2' srcipmask='128' dstipaddr='a:b:c::' dstipmask='65' protocol='icmpv6' type='1' code='10'/>
+  </rule>
+  <rule action='accept' direction='inout'>
+     <ipv6 srcipaddr='1::2' srcipmask='128' dstipaddr='a:b:c::' dstipmask='65' protocol='icmpv6' code='10'/>
+  </rule>
+  <rule action='accept' direction='inout'>
+     <ipv6 srcipaddr='1::2' srcipmask='128' dstipaddr='a:b:c::' dstipmask='65' protocol='icmpv6' type='1'/>
+  </rule>
 </filter>