extended ICMP packet dumping to parts after packet creation
[pingcheck] / src / ip / ipv4header.cpp
CommitLineData
0c0bb697
TJ
1// Copyright (c) 2003-2010 Christopher M. Kohlhoff
2// Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG
3//
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)
3bd915ea 7#include "ip/ipv4header.h"
4ea9706c 8
01e5134e
GMF
9#include <boost/scoped_array.hpp>
10
ba310c69
GMF
11#include <logfunc.hpp>
12
a4049623 13using namespace std;
2bf8720f 14using boost::asio::ip::address_v4;
5d9d2808 15using boost::asio::ip::address;
01e5134e 16using boost::scoped_array;
ba310c69 17using I2n::Logger::GlobalLogger;
a4049623 18
4c2a5ab5
GMF
19//-----------------------------------------------------------------------------
20// Ipv4Header
21//-----------------------------------------------------------------------------
22
5d9d2808 23static const size_t Ipv4HeaderSizeInBytes_withoutOptions = 20;
db21a81a 24
203750d4
GMF
25/**
26 * @brief Default constructor.
27 */
01e5134e 28Ipv4Header::Ipv4Header() :
6d80c0be 29 IpHeader( Ipv4HeaderSizeInBytes_withoutOptions )
4ea9706c 30{
747c13ca
CH
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);
4ea9706c 36}
0612cc8a 37
203750d4
GMF
38/**
39 * @brief Get the IP version.
40 *
41 * The Version field keeps track of which version of the protocol the
0612cc8a 42 * packet belongs to.
203750d4
GMF
43 *
44 * @return The 4-bits representing the Version field.
45 */
fd6ef587 46uint8_t Ipv4Header::get_version() const
4ea9706c 47{
01e5134e 48 return ( Payload[ 0 ] >> 4 ) & 0x0F;
4ea9706c
GMF
49}
50
203750d4
GMF
51/**
52 * @brief Get the header length.
53 *
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.
60 *
61 * @return A 16-bits number representing the size in bytes (not words) of
62 * the header.
63 */
fd6ef587 64uint16_t Ipv4Header::get_header_length() const
4ea9706c 65{
01e5134e 66 return static_cast<uint16_t>( (Payload[ 0 ] & 0x0F) * 4 );
4ea9706c
GMF
67}
68
203750d4 69/**
0612cc8a 70 * @brief Get the Differentiated Services, originally called Type of Service.
203750d4 71 *
0612cc8a 72 * The Differentiated Services field is used to provide QoS.
203750d4 73 *
0612cc8a 74 * @return The 8-bits representing the Differentiated Services.
203750d4 75 */
0612cc8a 76uint8_t Ipv4Header::get_differentiated_services() const
4ea9706c 77{
db21a81a 78 return Payload[ 1 ];
4ea9706c
GMF
79}
80
203750d4 81/**
2c8e193f 82 * @brief Get the packet Total Length in bytes.
203750d4
GMF
83 *
84 * The Total Length includes everything in the datagram - both header and data.
85 * The maximum length is 65,535 bytes.
86 *
87 * @return The 16-bits representing the packet's Total Length.
88 */
fd6ef587 89uint16_t Ipv4Header::get_total_length() const
4ea9706c 90{
01e5134e 91 return Payload.decode16( 2, 3 );
4ea9706c
GMF
92}
93
203750d4
GMF
94/**
95 * @brief Get the packet's fragment identification.
96 *
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.
100 *
101 * @return The 16-bits representing the packet identification number.
102 */
fd6ef587 103uint16_t Ipv4Header::get_identification() const
4ea9706c 104{
01e5134e 105 return Payload.decode16( 4, 5 );
4ea9706c
GMF
106}
107
203750d4
GMF
108/**
109 * @brief Get if the packet was ordered to don't be fragmented.
110 *
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.
114 *
115 * @return @c true if the packet was ordered to don't fragment, or @c false if
116 * it could be fragmented.
117 */
4ea9706c
GMF
118bool Ipv4Header::dont_fragment() const
119{
db21a81a 120 return ( ( Payload[ 6 ] & 0x40 ) != 0 );
4ea9706c
GMF
121}
122
203750d4
GMF
123/**
124 * @brief Get if this is the last fragment of a packet.
125 *
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.
128 *
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.
131 */
64c7fec3 132bool Ipv4Header::more_fragments() const
4ea9706c 133{
db21a81a 134 return ( ( Payload[ 6 ] & 0x20 ) != 0 );
4ea9706c
GMF
135}
136
203750d4
GMF
137/**
138 * @brief Get the packet's fragment offset.
139 *
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.
144 *
145 * @return The 13-bits representing the packet offset.
146 */
fd6ef587 147uint16_t Ipv4Header::get_fragment_offset() const
4ea9706c 148{
01e5134e 149 return Payload.decode16( 6, 7 ) & 0x1FFF;
4ea9706c
GMF
150}
151
203750d4
GMF
152/**
153 * @brief Get the time to live of the packet.
154 *
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.
157 *
158 * @return The 8-bit representing the Time to Live field.
159 */
703f4d65 160uint8_t Ipv4Header::get_time_to_live() const
4ea9706c 161{
db21a81a 162 return Payload[ 8 ];
4ea9706c
GMF
163}
164
203750d4
GMF
165/**
166 * @brief Get the identification of the transport protocol.
167 *
168 * The Protocol field tells which transport process to give the packet to.
169 *
170 * @return The 8-bits number representing the transport protocol.
171 */
fd6ef587 172uint8_t Ipv4Header::get_protocol() const
4ea9706c 173{
db21a81a 174 return Payload[ 9 ];
4ea9706c
GMF
175}
176
203750d4
GMF
177/**
178 * @brief Get the header checksum.
179 *
180 * The Header Checksum is used to protect the header data.
181 *
182 * @brief The 16-bits representing the header checksum.
183 */
fd6ef587 184uint16_t Ipv4Header::get_header_checksum() const
4ea9706c 185{
01e5134e 186 return Payload.decode16( 10, 11 );
4ea9706c
GMF
187}
188
203750d4
GMF
189/**
190 * @brief Get the source address.
191 *
264fbf88 192 * The Source Address field indicates the source network host address.
203750d4
GMF
193 *
194 * @brief The source address.
195 */
5d9d2808 196address Ipv4Header::get_source_address() const
4ea9706c 197{
01e5134e
GMF
198 uint32_t address = Payload.decode32( 12, 15 );
199
200 return address_v4( address );
4ea9706c
GMF
201}
202
203750d4
GMF
203/**
204 * @brief Get the destination address.
205 *
264fbf88 206 * The Destination Address field indicates the destination network host address.
203750d4
GMF
207 *
208 * @return The destination address.
209 */
5d9d2808 210address Ipv4Header::get_destination_address() const
4ea9706c 211{
01e5134e
GMF
212 uint32_t address = Payload.decode32( 16, 19 );
213
214 return address_v4( address );
4ea9706c
GMF
215}
216
a4049623
GMF
217istream &operator>>(
218 istream &is,
cb60ed91
GMF
219 Ipv4Header &header
220)
4ea9706c 221{
01e5134e
GMF
222 // read the first 20 bytes (mandatory for IP header) from the input stream
223 // and stores in the buffer object
ba310c69 224 (void) header.Payload.read( is );
db21a81a 225
4fdd6c59
CH
226 uint8_t header_version = header.get_version();
227 if ( header_version != 4 )
01e5134e 228 {
0fd358ca 229 GlobalLogger.error() << "Invalid IP header version: " << static_cast<int>(header_version) << endl;
2c5550a0 230
a4049623 231 is.setstate( ios::failbit );
4fdd6c59 232 return is;
01e5134e
GMF
233 }
234
235 // read the consecutive N bytes (for options field) from the input stream
236 // and stores in the buffer object
ba310c69 237 streamsize options_length = static_cast<streamsize>( header.get_header_length() ) -
5d9d2808 238 static_cast<streamsize>( Ipv4HeaderSizeInBytes_withoutOptions );
01e5134e 239 if ( ( options_length < 0 ) || ( 40 < options_length ) )
a4049623 240 {
0fd358ca 241 GlobalLogger.error() << "Invalid IP options length value:" << options_length << endl;
a4049623
GMF
242 is.setstate( ios::failbit );
243 }
ff9fdbd3 244 else if ( ( 0 < options_length ) && ( options_length <= 40 ) )
a4049623 245 {
ba310c69
GMF
246 size_t options_size = static_cast<size_t>( options_length );
247 scoped_array<uint8_t> options_data( new uint8_t[options_size] );
2c5550a0 248 memset(options_data.get(), 0, options_size*sizeof(uint8_t));
01e5134e 249 char *options_data_array = reinterpret_cast<char *>( options_data.get() );
a4049623 250
ba310c69 251 (void) is.read( options_data_array, options_length );
451c9121 252
ba310c69 253 header.Payload.append( options_data.get(), options_size );
01e5134e 254 }
ff9fdbd3
GMF
255 else // ( options_length == 0 )
256 {
257 //GlobalLogger.info() << "Info: No options available in this packet." << endl;
258 }
451c9121 259
01e5134e 260 return is;
4ea9706c 261}