2 The software in this package is distributed under the GNU General
3 Public License version 2 (with a special exception described below).
5 A copy of GNU General Public License (GPL) is included in this distribution,
6 in the file COPYING.GPL.
8 As a special exception, if other files instantiate templates or use macros
9 or inline functions from this file, or you compile this file and link it
10 with other works to produce a work based on this file, this file
11 does not by itself cause the resulting work to be covered
12 by the GNU General Public License.
14 However the source code for this file must still be made available
15 in accordance with section (3) of the GNU General Public License.
17 This exception does not invalidate any other reasons why a work based
18 on this file might be covered by the GNU General Public License.
20 Christian Herdtweck, Intra2net AG 2015
21 Based on an example in Boost Documentation (by Christopher M. Kohlhoff)
22 and adaptation by Guilherme M. Ferreira
25 #include "icmp/icmppacketfactory.h"
27 // for dumping packets
33 #include <boost/scoped_array.hpp>
35 #include <logfunc.hpp>
37 #include "boost_assert_handler.h"
38 #include "icmp/icmpdata.h"
39 #include "icmp/icmpheader.h"
40 #include "icmp/icmptype.h"
41 #include "icmp/icmpechodata.h"
42 #include "tools/pcap.h"
45 using boost::asio::ip::icmp;
46 using I2n::Logger::GlobalLogger;
48 void dump_packet(const std::string &data)
50 // create unique file name
51 std::stringstream temp_name;
52 temp_name << IcmpPacketFactory::DumpFilePrefix;
53 time_t capture_time = time(0);
54 temp_name << capture_time;
55 temp_name << "_XXXXXX.pcap";
56 std::string temp_str = temp_name.str();
57 std::size_t temp_size = temp_str.size();
58 boost::scoped_array<char> secure_filename( new char[temp_size + 1] );
59 std::copy(temp_str.begin(), temp_str.end(), secure_filename.get());
60 secure_filename[temp_size] = '\0';
61 int fd = mkstemps(secure_filename.get(), 5); // 5 = ".pcap".length
64 GlobalLogger.warning() << "Failed to create temp file "
65 << secure_filename.get() << ": " << strerror(errno) << "!" << endl;
66 // maybe create containing directory if errno == ENOENT?
70 // create file pointer for file descriptor
71 FILE *fp = fdopen(fd, "w");
74 write_pcap_packet_data(data, fp, capture_time);
79 GlobalLogger.debug() << "Dumped a copy of the data into "
80 << secure_filename.get() << endl;
82 //-----------------------------------------------------------------------------
84 //-----------------------------------------------------------------------------
87 DumpMode IcmpPacketFactory::PacketDumpMode = DUMP_IF_ERROR;
88 std::string IcmpPacketFactory::DumpFilePrefix = "/tmp/icmp_";
91 * @brief Creates an ICMP packet from the input stream @c std::istream.
93 * @param protocol The packet's network layer protocol, IPv4 or IPv6.
94 * @param is The input stream.
96 * @return An ICMP Packet object.
98 IcmpPacketItem IcmpPacketFactory::create_icmp_packet(
99 const icmp::socket::protocol_type &protocol,
103 IcmpPacketItem icmp_packet;
105 if ( icmp::v4() == protocol || icmp::v6() == protocol )
106 icmp_packet.reset( new IcmpPacket( protocol ) );
109 GlobalLogger.warning() << "ICMP packet creation failed: "
110 << "Unknown protocol, expect ICMP v4 or v6!" << endl;
111 icmp_packet.reset(); // --> (!icmp_packet) is true
115 IcmpPacket::ReadReturnCode return_code;
117 // create buffer for saving data in it
118 stringbuf data_backup;
119 bool have_backup = false;
121 // create backup and parse data
124 // read packet from stream, possibly copying data first
125 if (PacketDumpMode != DUMP_NEVER)
127 // read all data into backup
128 ostream backup_filler(&data_backup);
129 backup_filler << is.rdbuf();
131 // create a new stream from backup buffer
132 // and use that in read
133 istream is_2(&data_backup);
135 return_code = icmp_packet->read( is_2 );
138 return_code = icmp_packet->read( is );
140 catch ( const std::exception &ex )
142 GlobalLogger.notice() << "Exception during ICMP parse: " << ex.what()
148 GlobalLogger.notice() << "Exception during ICMP parse." << std::endl;
152 if ( return_code != IcmpPacket::ReadReturnCode_OK )
154 GlobalLogger.warning() << "ICMP packet creation failed: "
155 << IcmpPacket::return_code_to_string(return_code) << endl;
156 icmp_packet.reset(); // --> (!icmp_packet) is true
157 // --> icmp_pinger will not try to continue working with this packet
159 else if ( !is.good() )
161 GlobalLogger.warning() << "ICMP packet creation failed: "
162 << "Stream not good at end of creation!" << endl;
163 icmp_packet.reset(); // --> (!icmp_packet) is true
166 // dump data if had trouble with packet or dumping is set to always
167 if ( PacketDumpMode == DUMP_ALWAYS ||
168 ( PacketDumpMode == DUMP_IF_ERROR && !icmp_packet ) )
171 dump_packet(data_backup.str());
173 GlobalLogger.warning() << "Would like to dump packet but "
174 << "trouble occured before backup was created!";
178 GlobalLogger.debug() << "Read packet " << icmp_packet->to_string()
181 GlobalLogger.debug() << "Read packet failed" << endl;
187 * @brief Creates an ICMP Echo Request packet.
189 * @param protocol The packet's network layer protocol, IPv4 or IPv6.
190 * @param identifier The packet's identifier number to aid in matching Echo
191 * Replies to this Echo Request. May be zero.
192 * @param sequence_number The packet's sequence number to aid in matching Echo
193 * Replies to this Echo Request. May be zero.
195 * @return An ICMP Echo Request packet object.
197 IcmpPacketItem IcmpPacketFactory::create_icmp_packet_echo_request(
198 const icmp::socket::protocol_type &protocol,
199 const uint16_t identifier,
200 const uint16_t sequence_number
203 BOOST_ASSERT( (icmp::v4() == protocol) || (icmp::v6() == protocol) );
206 if ( icmp::v4() == protocol )
207 type = static_cast<uint8_t>(Icmpv4Type_EchoRequest);
208 else if ( icmp::v6() == protocol )
209 type = static_cast<uint8_t>(Icmpv6Type_EchoRequest);
210 // other case caught be BOOST_ASSERT above
213 IcmpHeader icmp_header( type, code );
215 IcmpDataPtr icmp_data( new IcmpEchoData( identifier, sequence_number,
218 IcmpPacketItem icmp_packet( new IcmpPacket( protocol,
221 GlobalLogger.debug() << "IcmpPacketFactory: created echo request packet"