Update pingcheck to work with cmake 3.28
[pingcheck] / src / ip / ipv4header.cpp
... / ...
CommitLineData
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)
7#include "ip/ipv4header.h"
8
9#include <boost/scoped_array.hpp>
10
11#include <logfunc.hpp>
12
13using namespace std;
14using boost::asio::ip::address_v4;
15using boost::asio::ip::address;
16using boost::scoped_array;
17using I2n::Logger::GlobalLogger;
18
19//-----------------------------------------------------------------------------
20// Ipv4Header
21//-----------------------------------------------------------------------------
22
23static const size_t Ipv4HeaderSizeInBytes_withoutOptions = 20;
24
25/**
26 * @brief Default constructor.
27 */
28Ipv4Header::Ipv4Header() :
29 IpHeader( Ipv4HeaderSizeInBytes_withoutOptions )
30{
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);
36}
37
38/**
39 * @brief Get the IP version.
40 *
41 * The Version field keeps track of which version of the protocol the
42 * packet belongs to.
43 *
44 * @return The 4-bits representing the Version field.
45 */
46uint8_t Ipv4Header::get_version() const
47{
48 return ( Payload[ 0 ] >> 4 ) & 0x0F;
49}
50
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 */
64uint16_t Ipv4Header::get_header_length() const
65{
66 return static_cast<uint16_t>( (Payload[ 0 ] & 0x0F) * 4 );
67}
68
69/**
70 * @brief Get the Differentiated Services, originally called Type of Service.
71 *
72 * The Differentiated Services field is used to provide QoS.
73 *
74 * @return The 8-bits representing the Differentiated Services.
75 */
76uint8_t Ipv4Header::get_differentiated_services() const
77{
78 return Payload[ 1 ];
79}
80
81/**
82 * @brief Get the packet Total Length in bytes.
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 */
89uint16_t Ipv4Header::get_total_length() const
90{
91 return Payload.decode16( 2, 3 );
92}
93
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 */
103uint16_t Ipv4Header::get_identification() const
104{
105 return Payload.decode16( 4, 5 );
106}
107
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 */
118bool Ipv4Header::dont_fragment() const
119{
120 return ( ( Payload[ 6 ] & 0x40 ) != 0 );
121}
122
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 */
132bool Ipv4Header::more_fragments() const
133{
134 return ( ( Payload[ 6 ] & 0x20 ) != 0 );
135}
136
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 */
147uint16_t Ipv4Header::get_fragment_offset() const
148{
149 return Payload.decode16( 6, 7 ) & 0x1FFF;
150}
151
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 */
160uint8_t Ipv4Header::get_time_to_live() const
161{
162 return Payload[ 8 ];
163}
164
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 */
172uint8_t Ipv4Header::get_protocol() const
173{
174 return Payload[ 9 ];
175}
176
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 */
184uint16_t Ipv4Header::get_header_checksum() const
185{
186 return Payload.decode16( 10, 11 );
187}
188
189/**
190 * @brief Get the source address.
191 *
192 * The Source Address field indicates the source network host address.
193 *
194 * @brief The source address.
195 */
196address Ipv4Header::get_source_address() const
197{
198 uint32_t address = Payload.decode32( 12, 15 );
199
200 return address_v4( address );
201}
202
203/**
204 * @brief Get the destination address.
205 *
206 * The Destination Address field indicates the destination network host address.
207 *
208 * @return The destination address.
209 */
210address Ipv4Header::get_destination_address() const
211{
212 uint32_t address = Payload.decode32( 16, 19 );
213
214 return address_v4( address );
215}
216
217istream &operator>>(
218 istream &is,
219 Ipv4Header &header
220)
221{
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 );
225
226 uint8_t header_version = header.get_version();
227 if ( header_version != 4 )
228 {
229 GlobalLogger.error() << "Invalid IP header version: " << static_cast<int>(header_version) << endl;
230
231 is.setstate( ios::failbit );
232 return is;
233 }
234
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 ) )
240 {
241 GlobalLogger.error() << "Invalid IP options length value:" << options_length << endl;
242 is.setstate( ios::failbit );
243 }
244 else if ( ( 0 < options_length ) && ( options_length <= 40 ) )
245 {
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() );
250
251 (void) is.read( options_data_array, options_length );
252
253 header.Payload.append( options_data.get(), options_size );
254 }
255 else // ( options_length == 0 )
256 {
257 //GlobalLogger.info() << "Info: No options available in this packet." << endl;
258 }
259
260 return is;
261}