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");
32NS_OBJECT_ENSURE_REGISTERED(V4TraceRoute);
33
34TypeId
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(Seconds(0)),
89 m_size(56),
90 m_socket(nullptr),
91 m_seq(0),
92 m_verbose(true),
93 m_probeCount(0),
94 m_maxProbes(3),
95 m_ttl(1),
96 m_maxTtl(30),
97 m_waitIcmpReplyTimeout(Seconds(5))
98{
99 m_osRoute.clear();
100 m_routeIpv4.clear();
101}
102
106
107void
112
113void
115{
116 NS_LOG_FUNCTION(this);
117 NS_LOG_LOGIC("Application started");
119
120 NS_ABORT_MSG_IF(!m_remote.IsInitialized(), "'Remote' attribute not properly set");
121
122 if (m_verbose)
123 {
124 NS_LOG_UNCOND("Traceroute to " << m_remote << ", " << m_maxTtl << " hops Max, " << m_size
125 << " bytes of data.");
126 }
127
128 if (m_printStream)
129 {
130 *m_printStream->GetStream() << "Traceroute to " << m_remote << ", " << m_maxTtl
131 << " hops Max, " << m_size << " bytes of data.\n";
132 }
133
134 m_socket = Socket::CreateSocket(GetNode(), TypeId::LookupByName("ns3::Ipv4RawSocketFactory"));
136 m_socket->SetIpTos(m_tos); // Affects only IPv4 sockets.
137
140
142 int status;
143 status = m_socket->Bind(src);
144 NS_ASSERT(status != -1);
145
147}
148
149void
151{
152 NS_LOG_FUNCTION(this);
153
154 if (m_next.IsPending())
155 {
156 m_next.Cancel();
157 }
158
160 {
162 }
163
164 if (m_socket)
165 {
166 m_socket->Close();
167 }
168
169 if (m_verbose)
170 {
171 NS_LOG_UNCOND("\nTrace Complete");
172 }
173
174 if (m_printStream)
175 {
176 *m_printStream->GetStream() << "Trace Complete\n" << std::endl;
177 }
178}
179
180void
182{
183 NS_LOG_FUNCTION(this);
184
186 {
188 }
189
190 m_socket = nullptr;
192}
193
196{
197 NS_LOG_FUNCTION(this);
198 Ptr<Node> node = GetNode();
199 for (uint32_t i = 0; i < node->GetNApplications(); ++i)
200 {
201 if (node->GetApplication(i) == this)
202 {
203 return i;
204 }
205 }
206 NS_ASSERT_MSG(false, "forgot to add application to node");
207 return 0;
208}
209
210void
212{
213 NS_LOG_FUNCTION(this << socket);
214
215 while (m_socket->GetRxAvailable() > 0)
216 {
217 Address from;
218 Ptr<Packet> p = m_socket->RecvFrom(0xffffffff, 0, from);
219 NS_LOG_DEBUG("recv " << p->GetSize() << " bytes");
222 NS_ASSERT(realFrom.GetPort() == 1);
223 Ipv4Header ipv4;
224 p->RemoveHeader(ipv4);
225 NS_ASSERT(ipv4.GetProtocol() == Icmpv4L4Protocol::PROT_NUMBER);
226 Icmpv4Header icmp;
227 p->RemoveHeader(icmp);
228
230 {
231 Icmpv4TimeExceeded timeoutResp;
232 p->RemoveHeader(timeoutResp);
233
234 // GetData () gets 64 bits of data, but the received packet
235 // only contains 32 bits of data.
236 uint8_t data[8];
237 timeoutResp.GetData(data);
238
239 // Get the 7th and 8th Octet to obtain the Sequence number from
240 // the original packet.
241 uint16_t recvSeq;
242 recvSeq = (uint16_t)data[7] << 0;
243 recvSeq |= (uint16_t)data[6] << 8;
244
245 auto i = m_sent.find(recvSeq);
246 if (i != m_sent.end())
247 {
248 Time sendTime = i->second;
249 NS_ASSERT(Simulator::Now() >= sendTime);
250 Time delta = Simulator::Now() - sendTime;
251
252 m_routeIpv4.str("");
253 m_routeIpv4.clear();
254 m_routeIpv4 << realFrom.GetIpv4();
255 m_osRoute << delta.As(Time::MS);
257 {
258 if (m_verbose)
259 {
260 NS_LOG_UNCOND(m_ttl << " " << m_routeIpv4.str() << " " << m_osRoute.str());
261 }
262
263 if (m_printStream)
264 {
265 *m_printStream->GetStream()
266 << m_ttl << " " << m_routeIpv4.str() << " " << m_osRoute.str() << "\n";
267 }
268 m_osRoute.str("");
269 m_osRoute.clear();
270 m_routeIpv4.str("");
271 m_routeIpv4.clear();
272 }
273 else
274 {
275 m_osRoute << " ";
276 }
277
279
280 if (m_ttl < m_maxTtl + 1)
281 {
282 m_next =
284 }
285 }
286 }
287 else if (icmp.GetType() == Icmpv4Header::ICMPV4_ECHO_REPLY &&
288 m_remote == realFrom.GetIpv4())
289 {
290 // When UDP is used, TraceRoute should stop until ICMPV4_DEST_UNREACH
291 // (with code (3) PORT_UNREACH) is received, however, the current
292 // ns-3 implementation does not include the UDP version of traceroute.
293 // The traceroute ICMP version (the current version) stops until max_ttl is reached
294 // or until an ICMP ECHO REPLY is received m_maxProbes times.
295
296 Icmpv4Echo echo;
297 p->RemoveHeader(echo);
298 auto i = m_sent.find(echo.GetSequenceNumber());
299
300 if (i != m_sent.end() && echo.GetIdentifier() == 0)
301 {
302 uint32_t dataSize = echo.GetDataSize();
303
304 if (dataSize == m_size)
305 {
306 Time sendTime = i->second;
307 NS_ASSERT(Simulator::Now() >= sendTime);
308 Time delta = Simulator::Now() - sendTime;
309
310 m_sent.erase(i);
311
312 if (m_verbose)
313 {
314 m_routeIpv4.str("");
315 m_routeIpv4.clear();
316 m_routeIpv4 << realFrom.GetIpv4();
317 m_osRoute << delta.As(Time::MS);
318
320 {
321 NS_LOG_UNCOND(m_ttl << " " << m_routeIpv4.str() << " "
322 << m_osRoute.str());
323 if (m_printStream)
324 {
325 *m_printStream->GetStream() << m_ttl << " " << m_routeIpv4.str()
326 << " " << m_osRoute.str() << "\n";
327 }
328
329 m_osRoute.clear();
330 m_routeIpv4.clear();
331 }
332 else
333 {
334 m_osRoute << " ";
335 }
336 }
337 }
338 }
339
342 {
343 if (m_verbose)
344 {
345 NS_LOG_UNCOND("\nTrace Complete");
346 }
347
348 if (m_printStream)
349 {
350 *m_printStream->GetStream() << "Trace Complete\n" << std::endl;
351 }
353 }
354 else if (m_ttl < m_maxTtl + 1)
355 {
357 }
358 }
359 }
360}
361
362void
364{
365 NS_LOG_INFO("m_seq=" << m_seq);
367 Icmpv4Echo echo;
369 m_seq++;
370 echo.SetIdentifier(0);
371
372 //
373 // We must write quantities out in some form of network order. Since there
374 // isn't an htonl to work with we just follow the convention in pcap traces
375 // (where any difference would show up anyway) and borrow that code. Don't
376 // be too surprised when you see that this is a little endian convention.
377 //
378 NS_ASSERT(m_size >= 16);
379
380 Ptr<Packet> dataPacket = Create<Packet>(m_size);
381 echo.SetData(dataPacket);
382 p->AddHeader(echo);
383 Icmpv4Header header;
385 header.SetCode(0);
387 {
388 header.EnableChecksum();
389 }
390
391 p->AddHeader(header);
392
394 {
395 m_probeCount++;
396 }
397 else
398 {
399 m_probeCount = 1;
400 m_ttl++;
401 }
402
403 m_sent.insert(std::make_pair(m_seq - 1, Simulator::Now()));
405
407 m_socket->SendTo(p, 0, dst);
408}
409
410void
412{
413 NS_LOG_FUNCTION(this);
415 {
416 NS_LOG_LOGIC("Starting WaitIcmpReplyTimer at " << Simulator::Now() << " for "
418
421 this);
422 Send();
423 }
424}
425
426void
428{
429 if (m_ttl < m_maxTtl + 1)
430 {
432 }
433
434 m_osRoute << "* ";
436 {
437 if (m_verbose)
438 {
439 NS_LOG_UNCOND(m_ttl << " " << m_routeIpv4.str() << " " << m_osRoute.str());
440 }
441
442 if (m_printStream)
443 {
444 *m_printStream->GetStream()
445 << m_ttl << " " << m_routeIpv4.str() << " " << m_osRoute.str() << "\n";
446 }
447 m_osRoute.str("");
448 m_osRoute.clear();
449 m_routeIpv4.str("");
450 m_routeIpv4.clear();
451 }
452}
453
454} // namespace ns3
a polymophic address class
Definition address.h:90
The base class for all ns3 applications.
Definition application.h:51
void DoDispose() override
Destructor implementation.
Ptr< Node > GetNode() const
AttributeValue implementation for Boolean.
Definition boolean.h:26
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition event-id.cc:44
bool IsPending() const
This method is syntactic sugar for !IsExpired().
Definition event-id.cc:65
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 const uint8_t PROT_NUMBER
ICMP protocol number (0x1)
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()
bool IsInitialized() const
AttributeValue implementation for Ipv4Address.
Packet header for IPv4.
Definition ipv4-header.h:23
static bool ChecksumEnabled()
Definition node.cc:267
void SetAttribute(std::string name, const AttributeValue &value)
Set a single attribute, raising fatal errors if unsuccessful.
Smart pointer class similar to boost::intrusive_ptr.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:560
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition simulator.h:594
virtual void SetIpTtl(uint8_t ipTtl)
Manually set IP Time to Live field.
Definition socket.cc:499
void SetIpTos(uint8_t ipTos)
Manually set IP Type of Service field.
Definition socket.cc:423
virtual Ptr< Packet > RecvFrom(uint32_t maxSize, uint32_t flags, Address &fromAddress)=0
Read a single packet from the socket and retrieve the sender address.
virtual uint32_t GetRxAvailable() const =0
Return number of bytes which can be returned from one or multiple calls to Recv.
void SetRecvCallback(Callback< void, Ptr< Socket > > receivedData)
Notify application when new data is available to be read.
Definition socket.cc:117
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
virtual int Close()=0
Close a socket.
virtual int Bind(const Address &address)=0
Allocate a local endpoint for this socket.
virtual int SendTo(Ptr< Packet > p, uint32_t flags, const Address &toAddress)=0
Send data to a specified peer.
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
@ MS
millisecond
Definition nstime.h:106
AttributeValue implementation for Time.
Definition nstime.h:1395
a unique identifier for an interface.
Definition type-id.h:48
static TypeId LookupByName(std::string name)
Get a TypeId by name.
Definition type-id.cc:872
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
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.
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
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition boolean.h:70
Ptr< const AttributeAccessor > MakeIpv4AddressAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeChecker > MakeIpv4AddressChecker()
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition nstime.h:1396
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1416
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition uinteger.h:35
#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:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:271
#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:264
#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:436
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1308
Every class exported by the ns3 library is enclosed in the ns3 namespace.
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:684
uint8_t data[writeSize]