1//
2// ICMPv4PacketImpl.cpp
3//
4// Library: Net
5// Package: ICMP
6// Module: ICMPv4PacketImpl
7//
8// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/Net/ICMPv4PacketImpl.h"
16#include "Poco/Net/NetException.h"
17#include "Poco/Timestamp.h"
18#include "Poco/Timespan.h"
19#include "Poco/NumberFormatter.h"
20#if !defined(POCO_VXWORKS)
21#include "Poco/Process.h"
22#endif
23#include <sstream>
24
25
26using Poco::InvalidArgumentException;
27using Poco::Timestamp;
28using Poco::Timespan;
29using Poco::NumberFormatter;
30using Poco::UInt8;
31using Poco::UInt16;
32using Poco::Int32;
33
34
35namespace Poco {
36namespace Net {
37
38
39const UInt8 ICMPv4PacketImpl::DESTINATION_UNREACHABLE_TYPE = 3;
40const Poco::UInt8 ICMPv4PacketImpl::SOURCE_QUENCH_TYPE = 4;
41const Poco::UInt8 ICMPv4PacketImpl::REDIRECT_MESSAGE_TYPE = 5;
42const UInt8 ICMPv4PacketImpl::TIME_EXCEEDED_TYPE = 11;
43const Poco::UInt8 ICMPv4PacketImpl::PARAMETER_PROBLEM_TYPE = 12;
44
45
46const std::string ICMPv4PacketImpl::MESSAGE_TYPE[] =
47{
48 "Echo Reply",
49 "ICMP 1",
50 "ICMP 2",
51 "Dest Unreachable",
52 "Source Quench",
53 "Redirect",
54 "ICMP 6",
55 "ICMP 7",
56 "Echo",
57 "ICMP 9",
58 "ICMP 10",
59 "Time Exceeded",
60 "Parameter Problem",
61 "Timestamp",
62 "Timestamp Reply",
63 "Info Request",
64 "Info Reply",
65 "Unknown type"
66};
67
68
69const std::string ICMPv4PacketImpl::DESTINATION_UNREACHABLE_CODE[] =
70{
71 "Net unreachable",
72 "Host unreachable",
73 "Protocol unreachable",
74 "Port unreachable",
75 "Fragmentation needed and DF set",
76 "Source route failed",
77 "Unknown code"
78};
79
80
81const std::string ICMPv4PacketImpl::REDIRECT_MESSAGE_CODE[] =
82{
83 "Redirect datagrams for the network",
84 "Redirect datagrams for the host",
85 "Redirect datagrams for the type of service and network",
86 "Redirect datagrams for the type of service and host",
87 "Unknown code"
88};
89
90
91const std::string ICMPv4PacketImpl::TIME_EXCEEDED_CODE[] =
92{
93 "Time to live exceeded in transit",
94 "Fragment reassembly time exceeded",
95 "Unknown code"
96};
97
98
99const std::string ICMPv4PacketImpl::PARAMETER_PROBLEM_CODE[] =
100{
101 "Pointer indicates the error",
102 "Unknown code"
103};
104
105
106ICMPv4PacketImpl::ICMPv4PacketImpl(int dataSize)
107 : ICMPPacketImpl(dataSize),
108 _seq(0)
109{
110 initPacket();
111}
112
113
114ICMPv4PacketImpl::~ICMPv4PacketImpl()
115{
116}
117
118
119int ICMPv4PacketImpl::packetSize() const
120{
121 return getDataSize() + sizeof(Header);
122}
123
124
125void ICMPv4PacketImpl::initPacket()
126{
127 if (_seq >= MAX_SEQ_VALUE) resetSequence();
128
129 Header* icp = (Header*) packet(false);
130 icp->type = ECHO_REQUEST;
131 icp->code = 0;
132 icp->checksum = 0;
133 icp->seq = ++_seq;
134#if defined(POCO_VXWORKS)
135 icp->id = 0;
136#else
137 icp->id = static_cast<UInt16>(Poco::Process::id());
138#endif
139
140 struct timeval* ptp = (struct timeval *) (icp + 1);
141 *ptp = time();
142
143 icp->checksum = checksum((UInt16*) icp, getDataSize() + sizeof(Header));
144}
145
146
147struct timeval ICMPv4PacketImpl::time(Poco::UInt8* buffer, int length) const
148{
149 struct timeval tv;
150
151 if (0 == buffer || 0 == length)
152 {
153 Timespan value(Timestamp().epochMicroseconds());
154 tv.tv_sec = (long) value.totalSeconds();
155 tv.tv_usec = (long) value.useconds();
156 }
157 else
158 {
159 struct timeval* ptv = (struct timeval*) data(buffer, length);
160 if (ptv) tv = *ptv;
161 else throw InvalidArgumentException("Invalid packet.");
162 }
163 return tv;
164}
165
166
167ICMPv4PacketImpl::Header* ICMPv4PacketImpl::header(Poco::UInt8* buffer, int length) const
168{
169 poco_check_ptr (buffer);
170
171 int offset = (buffer[0] & 0x0F) * 4;
172 if ((offset + sizeof(Header)) > length) return 0;
173
174 buffer += offset;
175 return (Header *) buffer;
176}
177
178
179Poco::UInt8* ICMPv4PacketImpl::data(Poco::UInt8* buffer, int length) const
180{
181 return ((Poco::UInt8*) header(buffer, length)) + sizeof(Header);
182}
183
184
185bool ICMPv4PacketImpl::validReplyID(Poco::UInt8* buffer, int length) const
186{
187 Header *icp = header(buffer, length);
188#if defined(POCO_VXWORKS)
189 return icp && icp->id == 0;
190#else
191 return icp && (static_cast<Poco::UInt16>(Process::id()) == icp->id);
192#endif
193}
194
195
196std::string ICMPv4PacketImpl::errorDescription(unsigned char* buffer, int length, int& type, int& code)
197{
198 Header *icp = header(buffer, length);
199
200 if (!icp) return "Invalid header.";
201 if (ECHO_REPLY == icp->type) return std::string(); // not an error
202
203 UInt8 pointer = 0;
204 if (PARAMETER_PROBLEM == icp->type)
205 {
206 UInt8 mask = 0x00FF;
207 pointer = icp->id & mask;
208 }
209
210 type = icp->type;
211 MessageType msgType = static_cast<MessageType>(type);
212 code = icp->code;
213 std::ostringstream err;
214
215 switch (msgType)
216 {
217 case DESTINATION_UNREACHABLE_TYPE:
218 if (code >= NET_UNREACHABLE && code < DESTINATION_UNREACHABLE_UNKNOWN)
219 err << DESTINATION_UNREACHABLE_CODE[code];
220 else
221 err << DESTINATION_UNREACHABLE_CODE[DESTINATION_UNREACHABLE_UNKNOWN];
222 break;
223
224 case SOURCE_QUENCH_TYPE:
225 err << "Source quench";
226 break;
227
228 case REDIRECT_MESSAGE_TYPE:
229 if (code >= REDIRECT_NETWORK && code < REDIRECT_MESSAGE_UNKNOWN)
230 err << REDIRECT_MESSAGE_CODE[code];
231 else
232 err << REDIRECT_MESSAGE_CODE[REDIRECT_MESSAGE_UNKNOWN];
233 break;
234
235 case TIME_EXCEEDED_TYPE:
236 if (code >= TIME_TO_LIVE && code < TIME_EXCEEDED_UNKNOWN)
237 err << TIME_EXCEEDED_CODE[code];
238 else
239 err << TIME_EXCEEDED_CODE[TIME_EXCEEDED_UNKNOWN];
240 break;
241
242 case PARAMETER_PROBLEM_TYPE:
243 if (POINTER_INDICATES_THE_ERROR != code)
244 code = PARAMETER_PROBLEM_UNKNOWN;
245 err << PARAMETER_PROBLEM_CODE[code] << ": error in octet #" << pointer;
246 break;
247
248 default:
249 err << "Unknown type.";
250 break;
251 }
252
253 return err.str();
254}
255
256std::string ICMPv4PacketImpl::typeDescription(int typeId)
257{
258 poco_assert (typeId >= ECHO_REPLY && typeId < MESSAGE_TYPE_LENGTH);
259
260 return MESSAGE_TYPE[typeId];
261}
262
263
264} } // namespace Poco::Net
265