prefix_ boost::uint16_t senf::Parse_IpV4::calcChecksum()
const
{
+ validate(bytes(*this));
IpChecksum summer;
summer.feed( i(), i()+checksum_offset );
// Not needed since the number of 0-bytes is even
{ return p->nextHeader(); }
static void dump(packet p, std::ostream & os);
+
+ static void finalize(packet p)
+ { p->nextHeader() << key(p.next()); }
};
/** \brief IpV6 fragment extension packet typedef */
//#include "IpV6Packet.ih"
// Custom includes
+#include <iomanip>
#include <boost/io/ios_state.hpp>
#include "EthernetPacket.hh"
#include "../../Socket/Protocols/INet/INetAddressing.hh"
{
boost::io::ios_all_saver ias(os);
os << "Internet protocol Version 6:\n"
- << " version : " << unsigned(p->version()) << "\n"
- << " traffic class : " << std::hex << unsigned(p->trafficClass()) << "\n"
- << " flow label : " << std::hex << unsigned(p->flowLabel()) << "\n"
- << " length : " << std::dec << unsigned(p->length()) << "\n"
- << " next header : " << unsigned(p->nextHeader()) << "\n"
- << " hop limit : " << unsigned(p->hopLimit()) << "\n"
- << " source : " << p->source() << "\n"
- << " destination : " << p->destination() << "\n";
+ << " version : " << unsigned(p->version()) << "\n"
+ << " traffic class : 0x"
+ << std::hex << std::setw(2) << std::setfill('0') << unsigned(p->trafficClass()) << "\n"
+ << " flow label : 0x"
+ << std::hex << std::setw(5) << std::setfill('0') << unsigned(p->flowLabel()) << "\n"
+ << " payload length : " << std::dec << unsigned(p->length()) << "\n"
+ << " next header : " << unsigned(p->nextHeader()) << "\n"
+ << " hop limit : " << unsigned(p->hopLimit()) << "\n"
+ << " source : " << p->source() << "\n"
+ << " destination : " << p->destination() << "\n";
+}
+
+prefix_ void senf::IpV6PacketType::finalize(packet p)
+{
+ p->length() << (p.size() - Parse_IpV6::fixed_bytes);
+ p->nextHeader() << key(p.next());
}
///////////////////////////////cc.e////////////////////////////////////////
{ return p->nextHeader(); }
static void dump(packet p, std::ostream & os);
+
+ static void finalize(packet p);
};
/** \brief IpV6 packet typedef */
#include "IpV4Packet.hh"
// Custom includes
+#include <iomanip>
+#include <boost/io/ios_state.hpp>
#include "../../Packets/Packets.hh"
+#include "../../Utils/IpChecksum.hh"
+#include "IpV4Packet.hh"
+#include "IpV6Packet.hh"
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
registerUDPPacket (17);
}
+///////////////////////////////////////////////////////////////////////////
+// senf::Parse_UDP
+
+prefix_ boost::uint16_t senf::Parse_UDP::calcChecksum()
+ const
+{
+ IpChecksum summer;
+ summer.feed( i(), i()+checksum_offset );
+ summer.feed( i()+checksum_offset+2, data().end() );
+
+ // Now on to the awkward part: the IP pseudo header
+ IpV4Packet ipv4 (packet().prev<IpV4Packet>(nothrow));
+ if (ipv4) {
+ // Pseudo header defined in RFC768
+ summer.feed( ipv4->source().i(),
+ ipv4->source().i() + Parse_IpV4::source_t::fixed_bytes );
+ ///\fixme What about a hop-by-hop routing option? Which destination is used in IpV4 ?
+ summer.feed( ipv4->destination().i(),
+ ipv4->destination().i() + Parse_IpV4::destination_t::fixed_bytes );
+ summer.feed( 0u );
+ ///\fixme May there be another header between the IpV4 header and UDP? if so, we
+ /// need to hack the correct protocol number here ...
+ summer.feed( 17u );
+ summer.feed( i() + length_offset, i() + length_offset + 2 );
+ }
+ else {
+ // Pseudo header defined in RFC2460
+ IpV6Packet ipv6 (packet().prev<IpV6Packet>(nothrow));
+ if (ipv6) {
+ summer.feed( ipv6->source().i(),
+ ipv6->source().i() + Parse_IpV6::source_t::fixed_bytes );
+ ///\todo Implement routing header support
+ // The destination used here must be the *final* destination ...
+ summer.feed( ipv6->destination().i(),
+ ipv6->destination().i() + Parse_IpV6::destination_t::fixed_bytes );
+ /// This is a simplification. The value is really 32bit to support UDP Jumbograms
+ /// (RFC2147). However, skipping an even number of 0 bytes does not change the checksum
+ summer.feed( i() + length_offset, i() + length_offset + 2 );
+ // RFC2460 specifies, that this must always be 17, not the value used in the ipv6
+ // header
+ summer.feed( 0u );
+ summer.feed( 17u );
+ }
+ }
+
+ boost::uint16_t rv (summer.sum());
+ return rv ? rv : 0xffffu;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::UDPPacketType
+
prefix_ void senf::UDPPacketType::dump(packet p, std::ostream & os)
{
+ boost::io::ios_all_saver ias(os);
os << "UDP:\n"
<< " source port : " << p->source() << "\n"
<< " dest port : " << p->destination() << "\n"
<< " length : " << p->length() << "\n"
- << " crc : " << std::hex << p->crc() << std::dec << "\n";
+ << " checksum : "
+ << std::hex << std::setw(4) << std::setfill('0') << p->checksum() << "\n";
+}
+
+prefix_ void senf::UDPPacketType::finalize(packet p)
+{
+ p->length() << p.size();
+ p->checksum() << p->calcChecksum();
}
///////////////////////////////cc.e////////////////////////////////////////
((Field)( source, Parse_16bit ))
((Field)( destination, Parse_16bit ))
((Field)( length, Parse_16bit ))
- ((Field)( crc, Parse_16bit )) );
+ ((Field)( checksum, Parse_16bit )) );
# else
Parse_16bit source();
Parse_16bit destination();
Parse_16bit length();
- Parse_16bit crc();
+ Parse_16bit checksum();
# endif
+
+ boost::uint16_t calcChecksum() const;
+ bool validateChecksum() const {
+ return checksum() == 0u || checksum() == calcChecksum();
+ }
};
/** \brief UDP packet
using mixin::init;
static void dump(packet p, std::ostream & os);
+
+ static void finalize(packet p);
};
/** \brief UDP packet typedef */
// Custom includes
#include "UDPPacket.hh"
+#include "IpV4Packet.hh"
#include <boost/test/auto_unit_test.hpp>
#include <boost/test/test_tools.hpp>
BOOST_CHECK_EQUAL( p->source(), 0x0102 );
BOOST_CHECK_EQUAL( p->destination(), 0x0304 );
BOOST_CHECK_EQUAL( p->length(), 0x0506 );
- BOOST_CHECK_EQUAL( p->crc(), 0x0708 );
-
+ BOOST_CHECK_EQUAL( p->checksum(), 0x0708 );
}
+BOOST_AUTO_UNIT_TEST(udpPacket_create)
+{
+ unsigned char data[] = { 0x45, 0x00, 0x00, 0x26, 0x00, 0x00, 0x40, 0x00,
+ 0x40, 0x11, 0x3c, 0xc5, 0x7f, 0x00, 0x00, 0x01,
+ 0x7f, 0x00, 0x00, 0x01, 0x5b, 0xa0, 0x30, 0x39,
+ 0x00, 0x12, 0xfa, 0x6e, 0x54, 0x45, 0x53, 0x54,
+ 0x2d, 0x57, 0x52, 0x49, 0x54, 0x45 };
+
+ senf::IpV4Packet ip (senf::IpV4Packet::create());
+ ip->source() = senf::INet4Address::Loopback;
+ ip->destination() = senf::INet4Address::Loopback;
+ ip->df() = true;
+ ip->ttl() = 64;
+
+ senf::UDPPacket udp (senf::UDPPacket::createAfter(ip));
+ udp->source() = 23456;
+ udp->destination() = 12345;
+
+ senf::DataPacket::createAfter(udp,std::string("TEST-WRITE"));
+
+ // validates, since the checksum is 0 and thus ignored !
+ BOOST_CHECK( udp->validateChecksum() );
+
+ ip.finalize();
+ BOOST_CHECK_EQUAL_COLLECTIONS( data, data+sizeof(data),
+ ip.data().begin(), ip.data().end() );
+ BOOST_CHECK( udp->validateChecksum() );
+}
///////////////////////////////cc.e////////////////////////////////////////
template <class PacketType>
friend class ConcretePacket;
+ friend class PacketParserBase;
};
/** \brief Protocol specific packet handle
friend class intrusive_refcount_t<PacketInterpreterBase>;
template <class PacketType> friend class PacketInterpreter;
friend class detail::packet::test::TestDriver;
+ friend class PacketParserBase;
};
/** \brief Internal: Concrete packet interpreter
const
{}
+prefix_ void senf::PacketParserBase::defaultInit()
+ const
+{}
+
+prefix_ senf::Packet senf::PacketParserBase::packet()
+ const
+{
+ // OUCH ... I hate this but for some awkward packet types, access to the packet
+ // from the parser is really needed (e.g. UDP when building the pseudo-header
+ // for calculating the checksum).
+ return Packet(PacketInterpreterBase::ptr(static_cast<PacketInterpreterBase*>(&data())));
+}
+
////////////////////////////////////////
// protected members
}
prefix_ bool senf::PacketParserBase::check(size_type size)
+ const
{
return size <= size_type(std::distance(i(),end()));
}
prefix_ void senf::PacketParserBase::validate(size_type size)
+ const
{
if (! check(size))
throw TruncatedPacketException();
// private members
prefix_ senf::PacketParserBase::data_iterator senf::PacketParserBase::end()
+ const
{
return data_->end();
}
return Parser(boost::next(i(),n),state());
}
-prefix_ void senf::PacketParserBase::defaultInit()
- const
-{}
-
///////////////////////////////////////////////////////////////////////////
// namespace members
///////////////////////////////hh.p////////////////////////////////////////
namespace senf {
+
+ class Packet;
/** \brief Parser Base class
container does not hold at least \a size bytes
beginning at \a i. */
- bool check(size_type size); ///< Check size of data container
+ bool check(size_type size) const; ///< Check size of data container
/**< \returns \c true, if the data container holds at least
\a size beginning at i(), \c false otherwise. */
- void validate(size_type size); ///< Validate size of data container
+ void validate(size_type size) const; ///< Validate size of data container
/**< \throws TruncatedPacketException if the raw data
container does not hold at least \a size bytes
beginning at i(). */
implementation. Re-implement this member in your own
parsers if needed. */
+ Packet packet() const; ///< Get packet this parser is parsing from
+ /**< \important This member should only be used from packet
+ parsers when access to previous or following packets is
+ needed e.g. for calculating checksums etc. */
+
private:
- data_iterator end();
+ data_iterator end() const;
data_iterator i_;
PacketData * data_;
type is not found in the registry, the returned
optional value will be empty. */
- ///@{
///\name PacketType interface implementation
+ ///@{
static PacketInterpreterBase::optional_range nextPacketRange (Packet p);
static PacketInterpreterBase::factory_t nextPacketType (Packet p);