Commit | Line | Data |
---|---|---|
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 | 13 | using namespace std; |
2bf8720f | 14 | using boost::asio::ip::address_v4; |
5d9d2808 | 15 | using boost::asio::ip::address; |
01e5134e | 16 | using boost::scoped_array; |
ba310c69 | 17 | using I2n::Logger::GlobalLogger; |
a4049623 | 18 | |
4c2a5ab5 GMF |
19 | //----------------------------------------------------------------------------- |
20 | // Ipv4Header | |
21 | //----------------------------------------------------------------------------- | |
22 | ||
5d9d2808 | 23 | static const size_t Ipv4HeaderSizeInBytes_withoutOptions = 20; |
db21a81a | 24 | |
203750d4 GMF |
25 | /** |
26 | * @brief Default constructor. | |
27 | */ | |
01e5134e | 28 | Ipv4Header::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 | 46 | uint8_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 | 64 | uint16_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 | 76 | uint8_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 | 89 | uint16_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 | 103 | uint16_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 |
118 | bool 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 | 132 | bool 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 | 147 | uint16_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 | 160 | uint8_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 | 172 | uint8_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 | 184 | uint16_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 | 196 | address 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 | 210 | address 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 |
217 | istream &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 | } |