From: g0dil Date: Mon, 8 Oct 2007 13:23:45 +0000 (+0000) Subject: Packets: Allow packet parsers to access the packet chain X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=a2bece00465e874b1a52e98918f64aa24919a009;p=senf.git Packets: Allow packet parsers to access the packet chain Packets/DefaultBundle: Implement IpV6Packet, IpV6Extensions and UDPPacket's finalize() git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@457 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Packets/DefaultBundle/IpV4Packet.cc b/Packets/DefaultBundle/IpV4Packet.cc index 8c55752..ec35159 100644 --- a/Packets/DefaultBundle/IpV4Packet.cc +++ b/Packets/DefaultBundle/IpV4Packet.cc @@ -52,6 +52,7 @@ namespace { 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 diff --git a/Packets/DefaultBundle/IpV6Extensions.hh b/Packets/DefaultBundle/IpV6Extensions.hh index a0bd5b0..37e74c7 100644 --- a/Packets/DefaultBundle/IpV6Extensions.hh +++ b/Packets/DefaultBundle/IpV6Extensions.hh @@ -101,6 +101,9 @@ namespace senf { { 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 */ diff --git a/Packets/DefaultBundle/IpV6Packet.cc b/Packets/DefaultBundle/IpV6Packet.cc index 2cf67b2..e96eaec 100644 --- a/Packets/DefaultBundle/IpV6Packet.cc +++ b/Packets/DefaultBundle/IpV6Packet.cc @@ -25,6 +25,7 @@ //#include "IpV6Packet.ih" // Custom includes +#include #include #include "EthernetPacket.hh" #include "../../Socket/Protocols/INet/INetAddressing.hh" @@ -48,14 +49,22 @@ prefix_ void senf::IpV6PacketType::dump(packet p, std::ostream & os) { 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//////////////////////////////////////// diff --git a/Packets/DefaultBundle/IpV6Packet.hh b/Packets/DefaultBundle/IpV6Packet.hh index f64652d..94a8799 100644 --- a/Packets/DefaultBundle/IpV6Packet.hh +++ b/Packets/DefaultBundle/IpV6Packet.hh @@ -131,6 +131,8 @@ namespace senf { { return p->nextHeader(); } static void dump(packet p, std::ostream & os); + + static void finalize(packet p); }; /** \brief IpV6 packet typedef */ diff --git a/Packets/DefaultBundle/UDPPacket.cc b/Packets/DefaultBundle/UDPPacket.cc index 5cf1f43..7ae0079 100644 --- a/Packets/DefaultBundle/UDPPacket.cc +++ b/Packets/DefaultBundle/UDPPacket.cc @@ -28,7 +28,12 @@ #include "IpV4Packet.hh" // Custom includes +#include +#include #include "../../Packets/Packets.hh" +#include "../../Utils/IpChecksum.hh" +#include "IpV4Packet.hh" +#include "IpV6Packet.hh" #define prefix_ ///////////////////////////////cc.p//////////////////////////////////////// @@ -38,13 +43,73 @@ namespace { 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(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(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//////////////////////////////////////// diff --git a/Packets/DefaultBundle/UDPPacket.hh b/Packets/DefaultBundle/UDPPacket.hh index e42bbc4..1e566a1 100644 --- a/Packets/DefaultBundle/UDPPacket.hh +++ b/Packets/DefaultBundle/UDPPacket.hh @@ -53,16 +53,21 @@ namespace senf { ((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 @@ -88,6 +93,8 @@ namespace senf { using mixin::init; static void dump(packet p, std::ostream & os); + + static void finalize(packet p); }; /** \brief UDP packet typedef */ diff --git a/Packets/DefaultBundle/UDPPacket.test.cc b/Packets/DefaultBundle/UDPPacket.test.cc index 347d5ac..d9d84c3 100644 --- a/Packets/DefaultBundle/UDPPacket.test.cc +++ b/Packets/DefaultBundle/UDPPacket.test.cc @@ -27,6 +27,7 @@ // Custom includes #include "UDPPacket.hh" +#include "IpV4Packet.hh" #include #include @@ -46,10 +47,37 @@ BOOST_AUTO_UNIT_TEST(udpPacket_packet) 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//////////////////////////////////////// diff --git a/Packets/Packet.hh b/Packets/Packet.hh index 206b8c8..59f7d56 100644 --- a/Packets/Packet.hh +++ b/Packets/Packet.hh @@ -384,6 +384,7 @@ namespace senf { template friend class ConcretePacket; + friend class PacketParserBase; }; /** \brief Protocol specific packet handle diff --git a/Packets/PacketInterpreter.hh b/Packets/PacketInterpreter.hh index 927d0ff..fe1b27a 100644 --- a/Packets/PacketInterpreter.hh +++ b/Packets/PacketInterpreter.hh @@ -212,6 +212,7 @@ namespace senf { friend class intrusive_refcount_t; template friend class PacketInterpreter; friend class detail::packet::test::TestDriver; + friend class PacketParserBase; }; /** \brief Internal: Concrete packet interpreter diff --git a/Packets/PacketParser.cci b/Packets/PacketParser.cci index 173e54e..ca79628 100644 --- a/Packets/PacketParser.cci +++ b/Packets/PacketParser.cci @@ -53,6 +53,19 @@ prefix_ void senf::PacketParserBase::init() 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(&data()))); +} + //////////////////////////////////////// // protected members @@ -68,11 +81,13 @@ prefix_ senf::PacketParserBase::PacketParserBase(data_iterator i, state_type s, } 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(); @@ -82,6 +97,7 @@ prefix_ void senf::PacketParserBase::validate(size_type size) // private members prefix_ senf::PacketParserBase::data_iterator senf::PacketParserBase::end() + const { return data_->end(); } diff --git a/Packets/PacketParser.cti b/Packets/PacketParser.cti index 28b71c2..5d27c62 100644 --- a/Packets/PacketParser.cti +++ b/Packets/PacketParser.cti @@ -46,10 +46,6 @@ prefix_ Parser senf::PacketParserBase::parse(size_type n) return Parser(boost::next(i(),n),state()); } -prefix_ void senf::PacketParserBase::defaultInit() - const -{} - /////////////////////////////////////////////////////////////////////////// // namespace members diff --git a/Packets/PacketParser.hh b/Packets/PacketParser.hh index c6a38e8..76b8252 100644 --- a/Packets/PacketParser.hh +++ b/Packets/PacketParser.hh @@ -159,6 +159,8 @@ ///////////////////////////////hh.p//////////////////////////////////////// namespace senf { + + class Packet; /** \brief Parser Base class @@ -292,10 +294,10 @@ namespace senf { 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(). */ @@ -314,8 +316,13 @@ namespace senf { 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_; diff --git a/Packets/PacketType.hh b/Packets/PacketType.hh index 53c17c1..88768f2 100644 --- a/Packets/PacketType.hh +++ b/Packets/PacketType.hh @@ -334,8 +334,8 @@ namespace senf { 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);