A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
v4traceroute.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2019 Ritsumeikan University, Shiga, Japan
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Alberto Gallegos Ramonet
7 *
8 * Traceroute uses ICMPV4 echo messages to trace all the middle hops to a given destination.
9 * It also shows the delay time it takes for a round trip to complete for each
10 * set probe (default 3).
11 *
12 */
13
14#include "v4traceroute.h"
15
16#include "ns3/assert.h"
17#include "ns3/boolean.h"
18#include "ns3/icmpv4-l4-protocol.h"
19#include "ns3/icmpv4.h"
20#include "ns3/inet-socket-address.h"
21#include "ns3/ipv4-address.h"
22#include "ns3/log.h"
23#include "ns3/packet.h"
24#include "ns3/socket.h"
25#include "ns3/trace-source-accessor.h"
26#include "ns3/uinteger.h"
27
28namespace ns3
29{
30
31NS_LOG_COMPONENT_DEFINE("V4TraceRoute");
33
36{
37 static TypeId tid =
38 TypeId("ns3::V4TraceRoute")
40 .SetGroupName("Internet-Apps")
41 .AddConstructor<V4TraceRoute>()
42 .AddAttribute("Remote",
43 "The address of the machine we want to trace.",
47 .AddAttribute("Tos",
48 "The Type of Service used to send IPv4 packets. "
49 "All 8 bits of the TOS byte are set (including ECN bits).",
53 .AddAttribute("Verbose",
54 "Produce usual output.",
55 BooleanValue(true),
58 .AddAttribute("Interval",
59 "Wait interval between sent packets.",
63 .AddAttribute("Size",
64 "The number of data bytes to be sent, real packet will "
65 "be 8 (ICMP) + 20 (IP) bytes longer.",
66 UintegerValue(56),
69 .AddAttribute("MaxHop",
70 "The maximum number of hops to trace.",
71 UintegerValue(30),
74 .AddAttribute("ProbeNum",
75 "The number of packets send to each hop.",
79 .AddAttribute("Timeout",
80 "The waiting time for a route response before a timeout.",
84 return tid;
85}
86
88 : m_interval(),
89 m_size(56),
90 m_socket(nullptr),
91 m_seq(0),
92 m_verbose(true),
93 m_traceComplete(false),
94 m_probeCount(0),
95 m_maxProbes(3),
96 m_ttl(1),
97 m_maxTtl(30),
99{
100 m_osRoute.clear();
101 m_routeIpv4.clear();
102}
103
107
108void
113
114void
116{
117 NS_LOG_FUNCTION(this);
118 NS_LOG_LOGIC("Application started");
119 m_traceComplete = false;
121
122 NS_ABORT_MSG_IF(m_remote.IsAny(), "'Remote' attribute not properly set");
123
124 if (m_verbose)
125 {
126 NS_LOG_UNCOND("Traceroute to " << m_remote << ", " << m_maxTtl << " hops Max, " << m_size
127 << " bytes of data.");
128 }
129
130 if (m_printStream)
131 {
132 *m_printStream->GetStream() << "Traceroute to " << m_remote << ", " << m_maxTtl
133 << " hops Max, " << m_size << " bytes of data.\n";
134 }
135
136 m_socket = Socket::CreateSocket(GetNode(), TypeId::LookupByName("ns3::Ipv4RawSocketFactory"));
137 m_socket->SetAttribute("Protocol", UintegerValue(Icmpv4L4Protocol::PROT_NUMBER));
138 m_socket->SetIpTos(m_tos); // Affects only IPv4 sockets.
139
141 m_socket->SetRecvCallback(MakeCallback(&V4TraceRoute::Receive, this));
142
144 int status;
145 status = m_socket->Bind(src);
146 NS_ASSERT(status != -1);
147
149}
150
151void
153{
154 NS_LOG_FUNCTION(this);
155
156 if (!m_traceComplete)
157 {
158 if (m_verbose)
159 {
160 NS_LOG_UNCOND("\nTrace Complete");
161 }
162
163 if (m_printStream)
164 {
165 *m_printStream->GetStream() << "Trace Complete\n" << std::endl;
166 }
167
168 m_traceComplete = true;
169 }
170
171 if (m_next.IsPending())
172 {
173 m_next.Cancel();
174 }
175
176 if (m_waitIcmpReplyTimer.IsPending())
177 {
178 m_waitIcmpReplyTimer.Cancel();
179 }
180
181 if (m_socket)
182 {
183 m_socket->Close();
184 }
185}
186
187void
189{
190 NS_LOG_FUNCTION(this);
191
192 if (m_next.IsPending() || m_waitIcmpReplyTimer.IsPending())
193 {
195 }
196
197 m_socket = nullptr;
199}
200
203{
204 NS_LOG_FUNCTION(this);
205 Ptr<Node> node = GetNode();
206 for (uint32_t i = 0; i < node->GetNApplications(); ++i)
207 {
208 if (node->GetApplication(i) == this)
209 {
210 return i;
211 }
212 }
213 NS_ASSERT_MSG(false, "forgot to add application to node");
214 return 0;
215}
216
217void
219{
220 NS_LOG_FUNCTION(this << socket);
221
222 while (m_socket->GetRxAvailable() > 0)
223 {
224 Address from;
225 Ptr<Packet> p = m_socket->RecvFrom(0xffffffff, 0, from);
226 NS_LOG_DEBUG("recv " << p->GetSize() << " bytes");
229 NS_ASSERT(realFrom.GetPort() == 1);
230 Ipv4Header ipv4;
231 p->RemoveHeader(ipv4);
232 NS_ASSERT(ipv4.GetProtocol() == Icmpv4L4Protocol::PROT_NUMBER);
233 Icmpv4Header icmp;
234 p->RemoveHeader(icmp);
235
237 {
238 Icmpv4TimeExceeded timeoutResp;
239 p->RemoveHeader(timeoutResp);
240
241 // GetData () gets 64 bits of data, but the received packet
242 // only contains 32 bits of data.
243 uint8_t data[8];
244 timeoutResp.GetData(data);
245
246 // Get the 7th and 8th Octet to obtain the Sequence number from
247 // the original packet.
248 uint16_t recvSeq;
249 recvSeq = (uint16_t)data[7] << 0;
250 recvSeq |= (uint16_t)data[6] << 8;
251
252 auto i = m_sent.find(recvSeq);
253 if (i != m_sent.end())
254 {
255 Time sendTime = i->second;
256 NS_ASSERT(Simulator::Now() >= sendTime);
257 Time delta = Simulator::Now() - sendTime;
258
259 m_routeIpv4.str("");
260 m_routeIpv4.clear();
261 m_routeIpv4 << realFrom.GetIpv4();
262 m_osRoute << delta.As(Time::MS);
264 {
265 if (m_verbose)
266 {
267 NS_LOG_UNCOND(m_ttl << " " << m_routeIpv4.str() << " " << m_osRoute.str());
268 }
269
270 if (m_printStream)
271 {
272 *m_printStream->GetStream()
273 << m_ttl << " " << m_routeIpv4.str() << " " << m_osRoute.str() << "\n";
274 }
275 m_osRoute.str("");
276 m_osRoute.clear();
277 m_routeIpv4.str("");
278 m_routeIpv4.clear();
279 }
280 else
281 {
282 m_osRoute << " ";
283 }
284
285 m_waitIcmpReplyTimer.Cancel();
286
287 if (m_ttl < m_maxTtl + 1)
288 {
289 m_next =
291 }
292 }
293 }
294 else if (icmp.GetType() == Icmpv4Header::ICMPV4_ECHO_REPLY &&
295 m_remote == realFrom.GetIpv4())
296 {
297 // When UDP is used, TraceRoute should stop until ICMPV4_DEST_UNREACH
298 // (with code (3) PORT_UNREACH) is received, however, the current
299 // ns-3 implementation does not include the UDP version of traceroute.
300 // The traceroute ICMP version (the current version) stops until max_ttl is reached
301 // or until an ICMP ECHO REPLY is received m_maxProbes times.
302
303 Icmpv4Echo echo;
304 p->RemoveHeader(echo);
305 auto i = m_sent.find(echo.GetSequenceNumber());
306
307 if (i != m_sent.end() && echo.GetIdentifier() == 0)
308 {
309 uint32_t dataSize = echo.GetDataSize();
310
311 if (dataSize == m_size)
312 {
313 Time sendTime = i->second;
314 NS_ASSERT(Simulator::Now() >= sendTime);
315 Time delta = Simulator::Now() - sendTime;
316
317 m_sent.erase(i);
318
319 if (m_verbose)
320 {
321 m_routeIpv4.str("");
322 m_routeIpv4.clear();
323 m_routeIpv4 << realFrom.GetIpv4();
324 m_osRoute << delta.As(Time::MS);
325
327 {
328 NS_LOG_UNCOND(m_ttl << " " << m_routeIpv4.str() << " "
329 << m_osRoute.str());
330 if (m_printStream)
331 {
332 *m_printStream->GetStream() << m_ttl << " " << m_routeIpv4.str()
333 << " " << m_osRoute.str() << "\n";
334 }
335
336 m_osRoute.clear();
337 m_routeIpv4.clear();
338 }
339 else
340 {
341 m_osRoute << " ";
342 }
343 }
344 }
345 }
346
347 m_waitIcmpReplyTimer.Cancel();
349 {
350 if (!m_traceComplete)
351 {
352 if (m_verbose)
353 {
354 NS_LOG_UNCOND("\nTrace Complete");
355 }
356 if (m_printStream)
357 {
358 *m_printStream->GetStream() << "Trace Complete\n" << std::endl;
359 }
360 m_traceComplete = true;
362 }
363 }
364 else if (m_ttl < m_maxTtl + 1)
365 {
367 }
368 }
369 }
370}
371
372void
374{
375 NS_LOG_INFO("m_seq=" << m_seq);
377 Icmpv4Echo echo;
379 m_seq++;
380 echo.SetIdentifier(0);
381
382 //
383 // We must write quantities out in some form of network order. Since there
384 // isn't an htonl to work with we just follow the convention in pcap traces
385 // (where any difference would show up anyway) and borrow that code. Don't
386 // be too surprised when you see that this is a little endian convention.
387 //
388 NS_ASSERT(m_size >= 16);
389
390 Ptr<Packet> dataPacket = Create<Packet>(m_size);
391 echo.SetData(dataPacket);
392 p->AddHeader(echo);
393 Icmpv4Header header;
395 header.SetCode(0);
397 {
398 header.EnableChecksum();
399 }
400
401 p->AddHeader(header);
402
404 {
405 m_probeCount++;
406 }
407 else
408 {
409 m_probeCount = 1;
410 m_ttl++;
411 }
412
413 m_sent.insert(std::make_pair(m_seq - 1, Simulator::Now()));
414 m_socket->SetIpTtl(m_ttl);
415
417 m_socket->SendTo(p, 0, dst);
418}
419
420void
422{
423 NS_LOG_FUNCTION(this);
424 if (!m_waitIcmpReplyTimer.IsPending())
425 {
426 NS_LOG_LOGIC("Starting WaitIcmpReplyTimer at " << Simulator::Now() << " for "
428
431 this);
432 Send();
433 }
434}
435
436void
438{
439 if (m_ttl < m_maxTtl + 1)
440 {
442 }
443
444 m_osRoute << "* ";
446 {
447 if (m_verbose)
448 {
449 NS_LOG_UNCOND(m_ttl << " " << m_routeIpv4.str() << " " << m_osRoute.str());
450 }
451
452 if (m_printStream)
453 {
454 *m_printStream->GetStream()
455 << m_ttl << " " << m_routeIpv4.str() << " " << m_osRoute.str() << "\n";
456 }
457 m_osRoute.str("");
458 m_osRoute.clear();
459 m_routeIpv4.str("");
460 m_routeIpv4.clear();
461 }
462}
463
464} // namespace ns3
a polymophic address class
Definition address.h:114
void DoDispose() override
Destructor implementation.
Ptr< Node > GetNode() const
ICMP Echo header.
Definition icmpv4.h:99
void SetIdentifier(uint16_t id)
Set the Echo identifier.
Definition icmpv4.cc:139
void SetData(Ptr< const Packet > data)
Set the Echo data.
Definition icmpv4.cc:153
uint16_t GetIdentifier() const
Get the Echo identifier.
Definition icmpv4.cc:175
void SetSequenceNumber(uint16_t seq)
Set the Echo sequence number.
Definition icmpv4.cc:146
uint32_t GetDataSize() const
Get the Echo data size.
Definition icmpv4.cc:189
uint16_t GetSequenceNumber() const
Get the Echo sequence number.
Definition icmpv4.cc:182
Base class for all the ICMP packet headers.
Definition icmpv4.h:32
void SetCode(uint8_t code)
Set ICMP code.
Definition icmpv4.cc:112
void SetType(uint8_t type)
Set ICMP type.
Definition icmpv4.cc:105
void EnableChecksum()
Enables ICMP Checksum calculation.
Definition icmpv4.cc:49
uint8_t GetType() const
Get ICMP type.
Definition icmpv4.cc:119
static constexpr uint8_t PROT_NUMBER
ICMP protocol number (see RFC 792).
ICMP Time Exceeded header.
Definition icmpv4.h:239
void GetData(uint8_t payload[8]) const
Get the ICMP carried data.
Definition icmpv4.cc:458
an Inet address class
static bool IsMatchingType(const Address &address)
Ipv4Address GetIpv4() const
static InetSocketAddress ConvertFrom(const Address &address)
Returns an InetSocketAddress which corresponds to the input Address.
static Ipv4Address GetAny()
Packet header for IPv4.
Definition ipv4-header.h:23
static bool ChecksumEnabled()
Definition node.cc:267
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:580
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:191
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition simulator.h:614
static Ptr< Socket > CreateSocket(Ptr< Node > node, TypeId tid)
This method wraps the creation of sockets that is performed on a given node by a SocketFactory specif...
Definition socket.cc:61
Simulation virtual time values and global simulation resolution.
Definition nstime.h:95
@ MS
millisecond
Definition nstime.h:107
a unique identifier for an interface.
Definition type-id.h:50
static TypeId LookupByName(std::string name)
Get a TypeId by name.
Definition type-id.cc:870
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:999
Hold an unsigned integer type.
Definition uinteger.h:34
Traceroute application sends one ICMP ECHO request with TTL=1, and after receiving an ICMP TIME EXCEE...
~V4TraceRoute() override
Ipv4Address m_remote
Remote address.
void HandleWaitReplyTimeout()
Triggers an action if an ICMP TIME EXCEED have not being received in the time defined by StartWaitRep...
void StopApplication() override
Application specific shutdown code.
EventId m_next
Next packet will be sent.
std::ostringstream m_routeIpv4
The Ipv4 address of the latest hop found.
void StartApplication() override
Application specific startup code.
bool m_traceComplete
True once completion output has been emitted.
Ptr< OutputStreamWrapper > m_printStream
Stream of the traceroute used for the output file.
uint32_t m_probeCount
The Current probe value.
uint16_t m_seq
ICMP ECHO sequence number.
uint32_t GetApplicationId() const
Return the application ID in the node.
uint16_t m_ttl
The current TTL value.
std::map< uint16_t, Time > m_sent
All sent but not answered packets. Map icmp seqno -> when sent.
void DoDispose() override
Destructor implementation.
Ptr< Socket > m_socket
The socket we send packets from.
uint32_t m_maxTtl
The maximum Ttl (Max number of hops to trace).
Time m_interval
Wait interval seconds between sending each packet.
void Print(Ptr< OutputStreamWrapper > stream)
Prints the application traced routes into a given OutputStream.
std::ostringstream m_osRoute
Stream of characters used for printing a single route.
Time m_started
Start time to report total ping time.
EventId m_waitIcmpReplyTimer
The timer used to wait for the probes ICMP replies.
uint32_t m_size
Specifies the number of data bytes to be sent.
uint8_t m_tos
The packets Type of Service.
uint16_t m_maxProbes
The maximum number of probe packets per hop.
Time m_waitIcmpReplyTimeout
The wait time until the response is considered lost.
void Receive(Ptr< Socket > socket)
Receive an ICMP Echo.
static TypeId GetTypeId()
Get the type ID.
void StartWaitReplyTimer()
Starts a timer after sending an ICMP ECHO.
bool m_verbose
produce traceroute style output if true
void Send()
Send one (ICMP ECHO) to the destination.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:690
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_LOG_UNCOND(msg)
Output the requested message unconditionally.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:194
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:260
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:274
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:267
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:492
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1273
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition nstime.h:1376
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition uinteger.h:35
Ptr< const AttributeAccessor > MakeIpv4AddressAccessor(T1 a1)
Ptr< const AttributeChecker > MakeIpv4AddressChecker()
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition boolean.h:70
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1396
uint8_t data[writeSize]