lte: (Fixes #2277) EpcTftClassifier::Classify blindly assumes that a packet has a L4 header

This commit is contained in:
Manuel Requena
2018-02-22 12:26:45 +01:00
parent c29225c68a
commit 1427607a3f
4 changed files with 161 additions and 54 deletions

View File

@@ -35,6 +35,7 @@ New user-visible features
Bugs fixed
----------
- Bug 1745 - There can be only one Ipv6AddressHelper in a script
- Bug 2277 - lte: EpcTftClassifier::Classify blindly assumes that a packet has a L4 header
- Bug 2505 - network: Avoid asserts in Header/Trailer deserialization
- Bug 2656 - wifi: Minstrel and MinstrelHt provide different results for 802.11a/b/g
- Bug 2653 - tcp: Avoid saving smaller TS in case of packet reordering

View File

@@ -48,10 +48,9 @@ EpcTftClassifier::EpcTftClassifier ()
void
EpcTftClassifier::Add (Ptr<EpcTft> tft, uint32_t id)
{
NS_LOG_FUNCTION (this << tft);
m_tftMap[id] = tft;
NS_LOG_FUNCTION (this << tft << id);
m_tftMap[id] = tft;
// simple sanity check: there shouldn't be more than 16 bearers (hence TFTs) per UE
NS_ASSERT (m_tftMap.size () <= 16);
}
@@ -67,7 +66,7 @@ EpcTftClassifier::Delete (uint32_t id)
uint32_t
EpcTftClassifier::Classify (Ptr<Packet> p, EpcTft::Direction direction)
{
NS_LOG_FUNCTION (this << p << direction);
NS_LOG_FUNCTION (this << p << p->GetSize () << direction);
Ptr<Packet> pCopy = p->Copy ();
@@ -105,8 +104,103 @@ EpcTftClassifier::Classify (Ptr<Packet> p, EpcTft::Direction direction)
}
NS_LOG_INFO ("local address: " << localAddressIpv4 << " remote address: " << remoteAddressIpv4);
uint16_t payloadSize = ipv4Header.GetPayloadSize ();
uint16_t fragmentOffset = ipv4Header.GetFragmentOffset ();
bool isLastFragment = ipv4Header.IsLastFragment ();
// NS_LOG_DEBUG ("PayloadSize = " << payloadSize);
// NS_LOG_DEBUG ("fragmentOffset " << fragmentOffset << " isLastFragment " << isLastFragment);
protocol = ipv4Header.GetProtocol ();
tos = ipv4Header.GetTos ();
// Port info only can be get if it is the first fragment and
// there is enough data in the payload
// We keep the port info for fragmented packets,
// i.e. it is the first one but it is not the last one
if (fragmentOffset == 0)
{
if (protocol == UdpL4Protocol::PROT_NUMBER && payloadSize >= 8)
{
UdpHeader udpHeader;
pCopy->RemoveHeader (udpHeader);
if (direction == EpcTft::UPLINK)
{
localPort = udpHeader.GetSourcePort ();
remotePort = udpHeader.GetDestinationPort ();
}
else
{
remotePort = udpHeader.GetSourcePort ();
localPort = udpHeader.GetDestinationPort ();
}
if (!isLastFragment)
{
std::tuple<uint32_t, uint32_t, uint8_t, uint16_t> fragmentKey =
std::make_tuple (ipv4Header.GetSource ().Get (),
ipv4Header.GetDestination ().Get (),
protocol,
ipv4Header.GetIdentification ());
m_classifiedIpv4Fragments[fragmentKey] = std::make_pair (localPort, remotePort);
}
}
else if (protocol == TcpL4Protocol::PROT_NUMBER && payloadSize >= 20)
{
TcpHeader tcpHeader;
pCopy->RemoveHeader (tcpHeader);
if (direction == EpcTft::UPLINK)
{
localPort = tcpHeader.GetSourcePort ();
remotePort = tcpHeader.GetDestinationPort ();
}
else
{
remotePort = tcpHeader.GetSourcePort ();
localPort = tcpHeader.GetDestinationPort ();
}
if (!isLastFragment)
{
std::tuple<uint32_t, uint32_t, uint8_t, uint16_t> fragmentKey =
std::make_tuple (ipv4Header.GetSource ().Get (),
ipv4Header.GetDestination ().Get (),
protocol,
ipv4Header.GetIdentification ());
m_classifiedIpv4Fragments[fragmentKey] = std::make_pair (localPort, remotePort);
}
}
// else
// First fragment but not enough data for port info or not UDP/TCP protocol.
// Nothing can be done, i.e. we cannot get port info from packet.
}
else
{
// Not first fragment, so port info is not available but
// port info should already be known (if there is not fragment reordering)
std::tuple<uint32_t, uint32_t, uint8_t, uint16_t> fragmentKey =
std::make_tuple (ipv4Header.GetSource ().Get (),
ipv4Header.GetDestination ().Get (),
protocol,
ipv4Header.GetIdentification ());
std::map< std::tuple<uint32_t, uint32_t, uint8_t, uint16_t>,
std::pair<uint32_t, uint32_t> >::iterator it =
m_classifiedIpv4Fragments.find (fragmentKey);
if (it != m_classifiedIpv4Fragments.end ())
{
localPort = it->second.first;
remotePort = it->second.second;
if (isLastFragment)
{
m_classifiedIpv4Fragments.erase (fragmentKey);
}
}
}
}
else if (ipType == 0x06)
{
@@ -128,53 +222,44 @@ EpcTftClassifier::Classify (Ptr<Packet> p, EpcTft::Direction direction)
protocol = ipv6Header.GetNextHeader ();
tos = ipv6Header.GetTrafficClass ();
if (protocol == UdpL4Protocol::PROT_NUMBER)
{
UdpHeader udpHeader;
pCopy->RemoveHeader (udpHeader);
if (direction == EpcTft::UPLINK)
{
localPort = udpHeader.GetSourcePort ();
remotePort = udpHeader.GetDestinationPort ();
}
else
{
remotePort = udpHeader.GetSourcePort ();
localPort = udpHeader.GetDestinationPort ();
}
}
else if (protocol == TcpL4Protocol::PROT_NUMBER)
{
TcpHeader tcpHeader;
pCopy->RemoveHeader (tcpHeader);
if (direction == EpcTft::UPLINK)
{
localPort = tcpHeader.GetSourcePort ();
remotePort = tcpHeader.GetDestinationPort ();
}
else
{
remotePort = tcpHeader.GetSourcePort ();
localPort = tcpHeader.GetDestinationPort ();
}
}
}
else
{
NS_ABORT_MSG ("EpcTftClassifier::Classify - Unknown IP type...");
}
if (protocol == UdpL4Protocol::PROT_NUMBER)
{
UdpHeader udpHeader;
pCopy->RemoveHeader (udpHeader);
if (direction == EpcTft::UPLINK)
{
localPort = udpHeader.GetSourcePort ();
remotePort = udpHeader.GetDestinationPort ();
}
else
{
remotePort = udpHeader.GetSourcePort ();
localPort = udpHeader.GetDestinationPort ();
}
}
else if (protocol == TcpL4Protocol::PROT_NUMBER)
{
TcpHeader tcpHeader;
pCopy->RemoveHeader (tcpHeader);
if (direction == EpcTft::UPLINK)
{
localPort = tcpHeader.GetSourcePort ();
remotePort = tcpHeader.GetDestinationPort ();
}
else
{
remotePort = tcpHeader.GetSourcePort ();
localPort = tcpHeader.GetDestinationPort ();
}
}
else if (protocol == Icmpv6L4Protocol::PROT_NUMBER || protocol == Icmpv4L4Protocol::PROT_NUMBER)
{
remotePort = 0;
localPort = 0;
}
else
{
NS_LOG_INFO ("Unknown protocol: " << protocol);
return 0; // no match
}
if (ipType == 0x04)
{

View File

@@ -36,9 +36,20 @@ class EpcTft;
class Packet;
/**
* \brief classifies IP packets accoding to Traffic Flow Templates (TFTs)
*
* \note this implementation works with IPv4 only.
* \brief classifies IP packets according to Traffic Flow Templates (TFTs)
*
* \note this implementation works with IPv4 and IPv6.
* When there is fragmentation of IP packets, UDP/TCP ports maybe missing.
*
* The following actions are performed to use the port info present in the first segment with
* the next fragments:
* - Port info is stored if it is available, i.e. it is the first fragment with UDP/TCP protocol
* and there is enough data in the payload of the IP packet for the port numbers.
* - Port info is used for the next fragments.
* - Port info is deleted, when the last fragment is processed.
*
* When we cannot cache the port info, the TFT of the default bearer is used. This may happen
* if there is reordering or losses of IP packets.
*/
class EpcTftClassifier : public SimpleRefCount<EpcTftClassifier>
{
@@ -76,7 +87,16 @@ public:
protected:
std::map <uint32_t, Ptr<EpcTft> > m_tftMap; ///< TFT map
std::map < std::tuple<uint32_t, uint32_t, uint8_t, uint16_t>,
std::pair<uint32_t, uint32_t> >
m_classifiedIpv4Fragments; ///< Map with already classified IPv4 Fragments
///< An entry is added when the port info is available, i.e.
///< first fragment, UDP/TCP protocols and enough payload data
///< An entry is used if port info is not available, i.e.
///< not first fragment or not enough payload data for TCP/UDP
///< An entry is removed when the last fragment is classified
///< Note: If last fragment is lost, entry is not removed
};

View File

@@ -116,14 +116,15 @@ EpcTftClassifierTestCase::EpcTftClassifierTestCase (Ptr<EpcTftClassifier> c,
m_d (d),
m_tftId (tftId)
{
NS_LOG_FUNCTION (this);
NS_LOG_FUNCTION (this << c << d << sa << da << sp << dp << tos << tftId);
m_ipHeader.SetSource (sa);
m_ipHeader.SetDestination (da);
m_ipHeader.SetTos (tos);
m_ipHeader.SetTos (tos);
m_ipHeader.SetPayloadSize (8); // Full UDP header
m_udpHeader.SetSourcePort (sp);
m_udpHeader.SetDestinationPort (dp);
m_udpHeader.SetDestinationPort (dp);
}
EpcTftClassifierTestCase::~EpcTftClassifierTestCase ()
@@ -163,7 +164,7 @@ EpcTftClassifierTestCase::DoRun (void)
udpPacket->AddHeader (m_ipHeader);
NS_LOG_LOGIC (this << *udpPacket);
uint32_t obtainedTftId = m_c ->Classify (udpPacket, m_d);
NS_TEST_ASSERT_MSG_EQ (obtainedTftId, m_tftId, "bad classification of UDP packet");
NS_TEST_ASSERT_MSG_EQ (obtainedTftId, (uint16_t) m_tftId, "bad classification of UDP packet");
}