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)
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 MessageType type = static_cast<MessageType>(icp->type);
211 int code = icp->code;
212 std::ostringstream err;
213
214 switch (type)
215 {
216 case DESTINATION_UNREACHABLE_TYPE:
217 if (code >= NET_UNREACHABLE && code < DESTINATION_UNREACHABLE_UNKNOWN)
218 err << DESTINATION_UNREACHABLE_CODE[code];
219 else
220 err << DESTINATION_UNREACHABLE_CODE[DESTINATION_UNREACHABLE_UNKNOWN];
221 break;
222
223 case SOURCE_QUENCH_TYPE:
224 err << "Source quench";
225 break;
226
227 case REDIRECT_MESSAGE_TYPE:
228 if (code >= REDIRECT_NETWORK && code < REDIRECT_MESSAGE_UNKNOWN)
229 err << REDIRECT_MESSAGE_CODE[code];
230 else
231 err << REDIRECT_MESSAGE_CODE[REDIRECT_MESSAGE_UNKNOWN];
232 break;
233
234 case TIME_EXCEEDED_TYPE:
235 if (code >= TIME_TO_LIVE && code < TIME_EXCEEDED_UNKNOWN)
236 err << TIME_EXCEEDED_CODE[code];
237 else
238 err << TIME_EXCEEDED_CODE[TIME_EXCEEDED_UNKNOWN];
239 break;
240
241 case PARAMETER_PROBLEM_TYPE:
242 if (POINTER_INDICATES_THE_ERROR != code)
243 code = PARAMETER_PROBLEM_UNKNOWN;
244 err << PARAMETER_PROBLEM_CODE[code] << ": error in octet #" << pointer;
245 break;
246
247 default:
248 err << "Unknown type.";
249 break;
250 }
251
252 return err.str();
253}
254
255std::string ICMPv4PacketImpl::typeDescription(int typeId)
256{
257 poco_assert (typeId >= ECHO_REPLY && typeId < MESSAGE_TYPE_LENGTH);
258
259 return MESSAGE_TYPE[typeId];
260}
261
262
263} } // namespace Poco::Net
264