Bug 1802 - FlowMon header deserialization problem with IPv4 fragments
authorTommaso Pecorella <tommaso.pecorella@unifi.it>
Mon, 02 Dec 2013 23:05:14 +0100
changeset 10467 c5bf751f8d4e
parent 10466 b891591b5b2a
child 10468 1ecb06d502cc
Bug 1802 - FlowMon header deserialization problem with IPv4 fragments
RELEASE_NOTES
src/flow-monitor/model/ipv4-flow-classifier.cc
--- a/RELEASE_NOTES	Tue Dec 03 17:06:35 2013 -0800
+++ b/RELEASE_NOTES	Mon Dec 02 23:05:14 2013 +0100
@@ -38,6 +38,7 @@
 - Bug 1777 - Implement the more direct way of "using" configuration of existing tap interface
 - Bug 1776 - Improve CRC performance for CsmaNetDevice in emulation modes
 - Bug 1798 - Changing the rate of onOffApplication might stop transmission
+- Bug 1802 - FlowMon header deserialization problem with IPv4 fragments
 - Bug 1807 - Multiple bugs in Ipv4L3Protocol::LocalDeliver
 
 Release 3.18.1
--- a/src/flow-monitor/model/ipv4-flow-classifier.cc	Tue Dec 03 17:06:35 2013 -0800
+++ b/src/flow-monitor/model/ipv4-flow-classifier.cc	Mon Dec 02 23:05:14 2013 +0100
@@ -109,35 +109,49 @@
       return false;
     }
 
+  if (ipHeader.GetFragmentOffset () > 0 )
+    {
+      // Ignore fragments: they don't carry a valid L4 header
+      return false;
+    }
+
   FiveTuple tuple;
   tuple.sourceAddress = ipHeader.GetSource ();
   tuple.destinationAddress = ipHeader.GetDestination ();
   tuple.protocol = ipHeader.GetProtocol ();
 
-  switch (tuple.protocol)
+  if ((tuple.protocol != UDP_PROT_NUMBER) && (tuple.protocol != TCP_PROT_NUMBER))
     {
-    case UDP_PROT_NUMBER:
-      {
-        UdpHeader udpHeader;
-        ipPayload->PeekHeader (udpHeader);
-        tuple.sourcePort = udpHeader.GetSourcePort ();
-        tuple.destinationPort = udpHeader.GetDestinationPort ();
-      }
-      break;
+      return false;
+    }
 
-    case TCP_PROT_NUMBER:
-      {
-        TcpHeader tcpHeader;
-        ipPayload->PeekHeader (tcpHeader);
-        tuple.sourcePort = tcpHeader.GetSourcePort ();
-        tuple.destinationPort = tcpHeader.GetDestinationPort ();
-      }
-      break;
-
-    default:
+  if (ipPayload->GetSize () < 4)
+    {
+      // the packet doesn't carry enough bytes
       return false;
     }
 
+  // we rely on the fact that for both TCP and UDP the ports are
+  // carried in the first 4 octects.
+  // This allows to read the ports even on fragmented packets
+  // not carrying a full TCP or UDP header.
+
+  uint8_t data[4];
+  ipPayload->CopyData (data, 4);
+
+  uint16_t srcPort = 0;
+  srcPort |= data[0];
+  srcPort <<= 8;
+  srcPort |= data[1];
+
+  uint16_t dstPort = 0;
+  dstPort |= data[2];
+  dstPort <<= 8;
+  dstPort |= data[3];
+
+  tuple.sourcePort = srcPort;
+  tuple.destinationPort = dstPort;
+
   // try to insert the tuple, but check if it already exists
   std::pair<std::map<FiveTuple, FlowId>::iterator, bool> insert
     = m_flowMap.insert (std::pair<FiveTuple, FlowId> (tuple, 0));