1 // Copyright (c) 2003-2010 Christopher M. Kohlhoff
2 // Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG
4 // Distributed under the Boost Software License, Version 1.0.
5 // (See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 #include "ip/ipv4header.h"
9 #include <boost/scoped_array.hpp>
11 #include <logfunc.hpp>
14 using boost::asio::ip::address_v4;
15 using boost::asio::ip::address;
16 using boost::scoped_array;
17 using I2n::Logger::GlobalLogger;
19 //-----------------------------------------------------------------------------
21 //-----------------------------------------------------------------------------
23 static const size_t Ipv4HeaderSizeInBytes_withoutOptions = 20;
26 * @brief Default constructor.
28 Ipv4Header::Ipv4Header() :
29 IpHeader( Ipv4HeaderSizeInBytes_withoutOptions )
31 // encode a 4 into the first 4 bits
32 Payload.encode1(0, 0, 0);
33 Payload.encode1(0, 1, 1);
34 Payload.encode1(0, 2, 0);
35 Payload.encode1(0, 3, 0);
39 * @brief Get the IP version.
41 * The Version field keeps track of which version of the protocol the
44 * @return The 4-bits representing the Version field.
46 uint8_t Ipv4Header::get_version() const
48 return ( Payload[ 0 ] >> 4 ) & 0x0F;
52 * @brief Get the header length.
54 * The Internet Header Length tells the number of 32-bit words in the header.
55 * Since an IPv4 header may contain a variable number of options, this field
56 * specifies the size of the header (this also coincides with the offset to
57 * the data). The minimum value for this field is 5 (RFC 791), which is a
58 * length of 5×32 = 160 bits = 20 bytes. Being a 4-bit value, the maximum
59 * length is 15 words (15×32 bits) or 480 bits = 60 bytes.
61 * @return A 16-bits number representing the size in bytes (not words) of
64 uint16_t Ipv4Header::get_header_length() const
66 return static_cast<uint16_t>( (Payload[ 0 ] & 0x0F) * 4 );
70 * @brief Get the Differentiated Services, originally called Type of Service.
72 * The Differentiated Services field is used to provide QoS.
74 * @return The 8-bits representing the Differentiated Services.
76 uint8_t Ipv4Header::get_differentiated_services() const
82 * @brief Get the packet Total Length in bytes.
84 * The Total Length includes everything in the datagram - both header and data.
85 * The maximum length is 65,535 bytes.
87 * @return The 16-bits representing the packet's Total Length.
89 uint16_t Ipv4Header::get_total_length() const
91 return Payload.decode16( 2, 3 );
95 * @brief Get the packet's fragment identification.
97 * The Identification field is needed to allow the destination host to
98 * determine which packet a newly arrived fragment belongs to. All the fragments
99 * of a packet contain the same Identification value.
101 * @return The 16-bits representing the packet identification number.
103 uint16_t Ipv4Header::get_identification() const
105 return Payload.decode16( 4, 5 );
109 * @brief Get if the packet was ordered to don't be fragmented.
111 * The DF field (Don't Fragment) is an order to the routers not to fragment the
112 * packet. It is used as part of the process to discover the path MTU, which is
113 * the largest packet that can travel along a path without being fragmented.
115 * @return @c true if the packet was ordered to don't fragment, or @c false if
116 * it could be fragmented.
118 bool Ipv4Header::dont_fragment() const
120 return ( ( Payload[ 6 ] & 0x40 ) != 0 );
124 * @brief Get if this is the last fragment of a packet.
126 * The MF field (More Fragments) is set to all fragments of a packet, except the
127 * last one. It is needed to know when all fragments of a datagram have arrived.
129 * @return @c false if this is the last fragment of a packet, or @c true if
130 * there are more fragments of this packet.
132 bool Ipv4Header::more_fragments() const
134 return ( ( Payload[ 6 ] & 0x20 ) != 0 );
138 * @brief Get the packet's fragment offset.
140 * The Fragment Offset field tells where in the current packet this fragment
141 * belongs. It is measured in units multiple of 8-bytes and specifies the offset
142 * of a particular fragment relative to the beginning of the original
143 * unfragmented IP datagram.
145 * @return The 13-bits representing the packet offset.
147 uint16_t Ipv4Header::get_fragment_offset() const
149 return Payload.decode16( 6, 7 ) & 0x1FFF;
153 * @brief Get the time to live of the packet.
155 * The Time to Live field is a counter used to limit packet lifetime. It must be
156 * decremented on each hop, and when it reaches zero it is discarded.
158 * @return The 8-bit representing the Time to Live field.
160 uint8_t Ipv4Header::get_time_to_live() const
166 * @brief Get the identification of the transport protocol.
168 * The Protocol field tells which transport process to give the packet to.
170 * @return The 8-bits number representing the transport protocol.
172 uint8_t Ipv4Header::get_protocol() const
178 * @brief Get the header checksum.
180 * The Header Checksum is used to protect the header data.
182 * @brief The 16-bits representing the header checksum.
184 uint16_t Ipv4Header::get_header_checksum() const
186 return Payload.decode16( 10, 11 );
190 * @brief Get the source address.
192 * The Source Address field indicates the source network host address.
194 * @brief The source address.
196 address Ipv4Header::get_source_address() const
198 uint32_t address = Payload.decode32( 12, 15 );
200 return address_v4( address );
204 * @brief Get the destination address.
206 * The Destination Address field indicates the destination network host address.
208 * @return The destination address.
210 address Ipv4Header::get_destination_address() const
212 uint32_t address = Payload.decode32( 16, 19 );
214 return address_v4( address );
222 // read the first 20 bytes (mandatory for IP header) from the input stream
223 // and stores in the buffer object
224 (void) header.Payload.read( is );
226 uint8_t header_version = header.get_version();
227 if ( header_version != 4 )
229 GlobalLogger.error() << "Invalid IP header version: " << static_cast<int>(header_version) << endl;
231 is.setstate( ios::failbit );
235 // read the consecutive N bytes (for options field) from the input stream
236 // and stores in the buffer object
237 streamsize options_length = static_cast<streamsize>( header.get_header_length() ) -
238 static_cast<streamsize>( Ipv4HeaderSizeInBytes_withoutOptions );
239 if ( ( options_length < 0 ) || ( 40 < options_length ) )
241 GlobalLogger.error() << "Invalid IP options length value:" << options_length << endl;
242 is.setstate( ios::failbit );
244 else if ( ( 0 < options_length ) && ( options_length <= 40 ) )
246 size_t options_size = static_cast<size_t>( options_length );
247 scoped_array<uint8_t> options_data( new uint8_t[options_size] );
248 memset(options_data.get(), 0, options_size*sizeof(uint8_t));
249 char *options_data_array = reinterpret_cast<char *>( options_data.get() );
251 (void) is.read( options_data_array, options_length );
253 header.Payload.append( options_data.get(), options_size );
255 else // ( options_length == 0 )
257 //GlobalLogger.info() << "Info: No options available in this packet." << endl;