// Copyright (c) 2003-2010 Christopher M. Kohlhoff // Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include "ip/ipv4header.h" #include #include using namespace std; using boost::asio::ip::address_v4; using boost::asio::ip::address; using boost::scoped_array; using I2n::Logger::GlobalLogger; //----------------------------------------------------------------------------- // Ipv4Header //----------------------------------------------------------------------------- static const size_t Ipv4HeaderSizeInBytes_withoutOptions = 20; /** * @brief Default constructor. */ Ipv4Header::Ipv4Header() : IpHeader( Ipv4HeaderSizeInBytes_withoutOptions ) { // encode a 4 into the first 4 bits Payload.encode1(0, 0, 0); Payload.encode1(0, 1, 1); Payload.encode1(0, 2, 0); Payload.encode1(0, 3, 0); } /** * @brief Get the IP version. * * The Version field keeps track of which version of the protocol the * packet belongs to. * * @return The 4-bits representing the Version field. */ uint8_t Ipv4Header::get_version() const { return ( Payload[ 0 ] >> 4 ) & 0x0F; } /** * @brief Get the header length. * * The Internet Header Length tells the number of 32-bit words in the header. * Since an IPv4 header may contain a variable number of options, this field * specifies the size of the header (this also coincides with the offset to * the data). The minimum value for this field is 5 (RFC 791), which is a * length of 5×32 = 160 bits = 20 bytes. Being a 4-bit value, the maximum * length is 15 words (15×32 bits) or 480 bits = 60 bytes. * * @return A 16-bits number representing the size in bytes (not words) of * the header. */ uint16_t Ipv4Header::get_header_length() const { return static_cast( (Payload[ 0 ] & 0x0F) * 4 ); } /** * @brief Get the Differentiated Services, originally called Type of Service. * * The Differentiated Services field is used to provide QoS. * * @return The 8-bits representing the Differentiated Services. */ uint8_t Ipv4Header::get_differentiated_services() const { return Payload[ 1 ]; } /** * @brief Get the packet Total Length in bytes. * * The Total Length includes everything in the datagram - both header and data. * The maximum length is 65,535 bytes. * * @return The 16-bits representing the packet's Total Length. */ uint16_t Ipv4Header::get_total_length() const { return Payload.decode16( 2, 3 ); } /** * @brief Get the packet's fragment identification. * * The Identification field is needed to allow the destination host to * determine which packet a newly arrived fragment belongs to. All the fragments * of a packet contain the same Identification value. * * @return The 16-bits representing the packet identification number. */ uint16_t Ipv4Header::get_identification() const { return Payload.decode16( 4, 5 ); } /** * @brief Get if the packet was ordered to don't be fragmented. * * The DF field (Don't Fragment) is an order to the routers not to fragment the * packet. It is used as part of the process to discover the path MTU, which is * the largest packet that can travel along a path without being fragmented. * * @return @c true if the packet was ordered to don't fragment, or @c false if * it could be fragmented. */ bool Ipv4Header::dont_fragment() const { return ( ( Payload[ 6 ] & 0x40 ) != 0 ); } /** * @brief Get if this is the last fragment of a packet. * * The MF field (More Fragments) is set to all fragments of a packet, except the * last one. It is needed to know when all fragments of a datagram have arrived. * * @return @c false if this is the last fragment of a packet, or @c true if * there are more fragments of this packet. */ bool Ipv4Header::more_fragments() const { return ( ( Payload[ 6 ] & 0x20 ) != 0 ); } /** * @brief Get the packet's fragment offset. * * The Fragment Offset field tells where in the current packet this fragment * belongs. It is measured in units multiple of 8-bytes and specifies the offset * of a particular fragment relative to the beginning of the original * unfragmented IP datagram. * * @return The 13-bits representing the packet offset. */ uint16_t Ipv4Header::get_fragment_offset() const { return Payload.decode16( 6, 7 ) & 0x1FFF; } /** * @brief Get the time to live of the packet. * * The Time to Live field is a counter used to limit packet lifetime. It must be * decremented on each hop, and when it reaches zero it is discarded. * * @return The 8-bit representing the Time to Live field. */ uint8_t Ipv4Header::get_time_to_live() const { return Payload[ 8 ]; } /** * @brief Get the identification of the transport protocol. * * The Protocol field tells which transport process to give the packet to. * * @return The 8-bits number representing the transport protocol. */ uint8_t Ipv4Header::get_protocol() const { return Payload[ 9 ]; } /** * @brief Get the header checksum. * * The Header Checksum is used to protect the header data. * * @brief The 16-bits representing the header checksum. */ uint16_t Ipv4Header::get_header_checksum() const { return Payload.decode16( 10, 11 ); } /** * @brief Get the source address. * * The Source Address field indicates the source network host address. * * @brief The source address. */ address Ipv4Header::get_source_address() const { uint32_t address = Payload.decode32( 12, 15 ); return address_v4( address ); } /** * @brief Get the destination address. * * The Destination Address field indicates the destination network host address. * * @return The destination address. */ address Ipv4Header::get_destination_address() const { uint32_t address = Payload.decode32( 16, 19 ); return address_v4( address ); } istream &operator>>( istream &is, Ipv4Header &header ) { // read the first 20 bytes (mandatory for IP header) from the input stream // and stores in the buffer object (void) header.Payload.read( is ); uint8_t header_version = header.get_version(); if ( header_version != 4 ) { GlobalLogger.error() << "Invalid IP header version: " << static_cast(header_version) << endl; is.setstate( ios::failbit ); return is; } // read the consecutive N bytes (for options field) from the input stream // and stores in the buffer object streamsize options_length = static_cast( header.get_header_length() ) - static_cast( Ipv4HeaderSizeInBytes_withoutOptions ); if ( ( options_length < 0 ) || ( 40 < options_length ) ) { GlobalLogger.error() << "Invalid IP options length value:" << options_length << endl; is.setstate( ios::failbit ); } else if ( ( 0 < options_length ) && ( options_length <= 40 ) ) { size_t options_size = static_cast( options_length ); scoped_array options_data( new uint8_t[options_size] ); memset(options_data.get(), 0, options_size*sizeof(uint8_t)); char *options_data_array = reinterpret_cast( options_data.get() ); (void) is.read( options_data_array, options_length ); header.Payload.append( options_data.get(), options_size ); } else // ( options_length == 0 ) { //GlobalLogger.info() << "Info: No options available in this packet." << endl; } return is; }