A Discrete-Event Network Simulator
API
v4traceroute.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2019 Ritsumeikan University, Shiga, Japan
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Alberto Gallegos Ramonet
19  *
20  * Traceroute uses ICMPV4 echo messages to trace all the middle hops to a given destination.
21  * It also shows the delay time it takes for a round trip to complete for each
22  * set probe (default 3).
23  *
24  */
25 
26 
27 #include "v4traceroute.h"
28 #include "ns3/icmpv4.h"
29 #include "ns3/icmpv4-l4-protocol.h"
30 #include "ns3/assert.h"
31 #include "ns3/log.h"
32 #include "ns3/ipv4-address.h"
33 #include "ns3/socket.h"
34 #include "ns3/uinteger.h"
35 #include "ns3/boolean.h"
36 #include "ns3/inet-socket-address.h"
37 #include "ns3/packet.h"
38 #include "ns3/trace-source-accessor.h"
39 
40 
41 namespace ns3 {
42 
43 NS_LOG_COMPONENT_DEFINE ("V4TraceRoute");
44 NS_OBJECT_ENSURE_REGISTERED (V4TraceRoute);
45 
46 TypeId
48 {
49  static TypeId tid = TypeId ("ns3::V4TraceRoute")
51  .SetGroupName ("Internet-Apps")
52  .AddConstructor<V4TraceRoute> ()
53  .AddAttribute ("Remote",
54  "The address of the machine we want to trace.",
58  .AddAttribute ("Verbose",
59  "Produce usual output.",
60  BooleanValue (true),
63  .AddAttribute ("Interval", "Wait interval between sent packets.",
64  TimeValue (Seconds (0)),
66  MakeTimeChecker ())
67  .AddAttribute ("Size", "The number of data bytes to be sent, real packet will be 8 (ICMP) + 20 (IP) bytes longer.",
68  UintegerValue (56),
70  MakeUintegerChecker<uint32_t> ())
71  .AddAttribute ("MaxHop", "The maximum number of hops to trace.",
72  UintegerValue (30),
74  MakeUintegerChecker<uint32_t> ())
75  .AddAttribute ("ProbeNum", "The number of packets send to each hop.",
76  UintegerValue (3),
78  MakeUintegerChecker<uint16_t> ())
79  .AddAttribute ("Timeout", "The waiting time for a route response before a timeout.",
80  TimeValue (Seconds (5)),
82  MakeTimeChecker ())
83  ;
84  return tid;
85 }
86 
87 
89  : m_interval (Seconds (0)),
90  m_size (56),
91  m_socket (0),
92  m_seq (0),
93  m_verbose (true),
94  m_probeCount (0),
95  m_maxProbes (3),
96  m_ttl (1),
97  m_maxTtl (30),
98  m_waitIcmpReplyTimeout (Seconds (5))
99 {
100  m_osRoute.clear ();
101  m_routeIpv4.clear ();
102 }
103 
105 {
106 
107 }
108 
109 
110 void
112 {
113  m_printStream = stream;
114 }
115 
116 void
118 {
119  NS_LOG_FUNCTION (this);
120  NS_LOG_LOGIC ("Application started");
122 
123  if (m_verbose)
124  {
125  NS_LOG_UNCOND("Traceroute to " << m_remote << ", "
126  << m_maxTtl << " hops Max, "
127  << m_size << " bytes of data.");
128  }
129 
130  if (m_printStream != NULL)
131  {
132  *m_printStream->GetStream () << "Traceroute to " << m_remote << ", "
133  << m_maxTtl << " hops Max, "
134  << m_size << " bytes of data.\n";
135  }
136 
137 
138  m_socket = Socket::CreateSocket (GetNode (), TypeId::LookupByName ("ns3::Ipv4RawSocketFactory"));
140 
141 
142  NS_ASSERT (m_socket != 0);
144 
146  int status;
147  status = m_socket->Bind (src);
148  NS_ASSERT (status != -1);
149 
151 }
152 
153 
154 
155 void
157 {
158  NS_LOG_FUNCTION (this);
159 
160  if (m_next.IsRunning ())
161  {
162  m_next.Cancel ();
163  }
164 
166  {
168  }
169 
170  if (m_socket)
171  {
172  m_socket->Close ();
173  }
174 }
175 
176 void
178 {
179  NS_LOG_FUNCTION (this);
180 
182  {
183  StopApplication ();
184  }
185 
186  m_socket = 0;
188 }
189 
190 
191 uint32_t
193 {
194  NS_LOG_FUNCTION (this);
195  Ptr<Node> node = GetNode ();
196  for (uint32_t i = 0; i < node->GetNApplications (); ++i)
197  {
198  if (node->GetApplication (i) == this)
199  {
200  return i;
201  }
202  }
203  NS_ASSERT_MSG (false, "forgot to add application to node");
204  return 0;
205 }
206 
207 void
209 {
210  NS_LOG_FUNCTION (this << socket);
211 
212  while (m_socket->GetRxAvailable () > 0)
213  {
214  Address from;
215  Ptr<Packet> p = m_socket->RecvFrom (0xffffffff, 0, from);
216  NS_LOG_DEBUG ("recv " << p->GetSize () << " bytes");
219  NS_ASSERT (realFrom.GetPort () == 1);
220  Ipv4Header ipv4;
221  p->RemoveHeader (ipv4);
223  Icmpv4Header icmp;
224  p->RemoveHeader (icmp);
225 
226 
227 
229  {
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 Octect 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 
246  std::map<uint16_t, Time>::iterator i = m_sent.find (recvSeq);
247  if (i != m_sent.end ())
248  {
249  Time sendTime = i->second;
250  NS_ASSERT (Simulator::Now () >= sendTime);
251  Time delta = Simulator::Now () - sendTime;
252 
253  m_routeIpv4.str ("");
254  m_routeIpv4.clear ();
255  m_routeIpv4 << realFrom.GetIpv4 ();
256  m_osRoute << delta.As (Time::MS);
257  if (m_probeCount == m_maxProbes)
258  {
259  if (m_verbose)
260  {
261  NS_LOG_UNCOND(m_ttl << " " << m_routeIpv4.str () << " " << m_osRoute.str ());
262  }
263 
264  if (m_printStream != NULL)
265  {
266  *m_printStream->GetStream () << m_ttl << " "
267  << m_routeIpv4.str () << " "
268  << m_osRoute.str () << "\n";
269  }
270  m_osRoute.str ("");
271  m_osRoute.clear ();
272  m_routeIpv4.str ("");
273  m_routeIpv4.clear ();
274  }
275  else
276  {
277  m_osRoute << " ";
278  }
279 
281 
282  if (m_ttl < m_maxTtl + 1)
283  {
285  }
286  }
287 
288  }
289  else if (icmp.GetType () == Icmpv4Header::ICMPV4_ECHO_REPLY && m_remote == realFrom.GetIpv4 ())
290  {
291  // When UDP is used, TraceRoute should stop until ICMPV4_DEST_UNREACH
292  // (with code (3) PORT_UNREACH) is received, however, the current
293  // ns-3 implementation does not include the UDP version of traceroute.
294  // The traceroute ICMP version (the current version) stops until max_ttl is reached
295  // or until an ICMP ECHO REPLY is received m_maxProbes times.
296 
297  Icmpv4Echo echo;
298  p->RemoveHeader (echo);
299  std::map<uint16_t, Time>::iterator i = m_sent.find (echo.GetSequenceNumber ());
300 
301  if (i != m_sent.end () && echo.GetIdentifier () == 0)
302  {
303  uint32_t dataSize = echo.GetDataSize ();
304 
305  if (dataSize == m_size)
306  {
307  Time sendTime = i->second;
308  NS_ASSERT (Simulator::Now () >= sendTime);
309  Time delta = Simulator::Now () - sendTime;
310 
311  m_sent.erase (i);
312 
313  if (m_verbose)
314  {
315  m_routeIpv4.str ("");
316  m_routeIpv4.clear ();
317  m_routeIpv4 << realFrom.GetIpv4 ();
318  m_osRoute << delta.As (Time::MS);
319 
320  if (m_probeCount == m_maxProbes)
321  {
322  NS_LOG_UNCOND(m_ttl << " " << m_routeIpv4.str () << " " << m_osRoute.str ());
323  if (m_printStream != NULL)
324  {
325  *m_printStream->GetStream () << m_ttl << " "
326  << m_routeIpv4.str () << " "
327  << m_osRoute.str () << "\n";
328  }
329 
330  m_osRoute.clear ();
331  m_routeIpv4.clear ();
332  }
333  else
334  {
335  m_osRoute << " ";
336  }
337  }
338  }
339  }
340 
342  if (m_probeCount == m_maxProbes)
343  {
344  if (m_verbose)
345  {
346  NS_LOG_UNCOND ("\nTrace Complete");
347  }
348 
349  if (m_printStream != NULL)
350  {
351  *m_printStream->GetStream () << "Trace Complete\n" << std::endl;
352  }
354  }
355  else if (m_ttl < m_maxTtl + 1)
356  {
358  }
359  }
360  }
361 }
362 
363 
364 
365 
366 void
368 {
369  NS_LOG_INFO ("m_seq=" << m_seq);
370  Ptr<Packet> p = Create<Packet> ();
371  Icmpv4Echo echo;
372  echo.SetSequenceNumber (m_seq);
373  m_seq++;
374  echo.SetIdentifier (0);
375 
376  //
377  // We must write quantities out in some form of network order. Since there
378  // isn't an htonl to work with we just follow the convention in pcap traces
379  // (where any difference would show up anyway) and borrow that code. Don't
380  // be too surprised when you see that this is a little endian convention.
381  //
382  NS_ASSERT (m_size >= 16);
383 
384  Ptr<Packet> dataPacket = Create<Packet> (m_size);
385  echo.SetData (dataPacket);
386  p->AddHeader (echo);
387  Icmpv4Header header;
389  header.SetCode (0);
390  if (Node::ChecksumEnabled ())
391  {
392  header.EnableChecksum ();
393  }
394 
395  p->AddHeader (header);
396 
398  {
399  m_probeCount++;
400  }
401  else
402  {
403  m_probeCount = 1;
404  m_ttl++;
405  }
406 
407  m_sent.insert (std::make_pair (m_seq - 1, Simulator::Now ()));
409 
410 
412  m_socket->SendTo (p, 0, dst);
413 }
414 
415 
416 void
418 {
419  NS_LOG_FUNCTION (this);
421  {
422  NS_LOG_LOGIC ("Starting WaitIcmpReplyTimer at " << Simulator::Now () << " for " <<
424 
427  Send ();
428  }
429 }
430 
431 
432 void
434 {
435  if (m_ttl < m_maxTtl + 1)
436  {
438  }
439 
440  m_osRoute << "* ";
441  if (m_probeCount == m_maxProbes)
442  {
443  if (m_verbose)
444  {
445  NS_LOG_UNCOND(m_ttl << " " << m_routeIpv4.str () << " " << m_osRoute.str ());
446  }
447 
448  if (m_printStream != NULL)
449  {
451  << " " << m_routeIpv4.str () << " "
452  << m_osRoute.str () << "\n";
453  }
454  m_osRoute.str ("");
455  m_osRoute.clear ();
456  m_routeIpv4.str ("");
457  m_routeIpv4.clear ();
458  }
459 }
460 
461 
462 } // ns3 namespace
a polymophic address class
Definition: address.h:91
The base class for all ns3 applications.
Definition: application.h:61
virtual void DoDispose(void)
Destructor implementation.
Definition: application.cc:83
Ptr< Node > GetNode() const
Definition: application.cc:104
AttributeValue implementation for Boolean.
Definition: boolean.h:37
bool IsRunning(void) const
This method is syntactic sugar for !IsExpired().
Definition: event-id.cc:71
void Cancel(void)
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition: event-id.cc:53
ICMP Echo header.
Definition: icmpv4.h:108
uint16_t GetSequenceNumber(void) const
Get the Echo sequence number.
Definition: icmpv4.cc:179
void SetIdentifier(uint16_t id)
Set the Echo identifier.
Definition: icmpv4.cc:140
void SetData(Ptr< const Packet > data)
Set the Echo data.
Definition: icmpv4.cc:152
uint16_t GetIdentifier(void) const
Get the Echo identifier.
Definition: icmpv4.cc:173
uint32_t GetDataSize(void) const
Get the Echo data size.
Definition: icmpv4.cc:185
void SetSequenceNumber(uint16_t seq)
Set the Echo sequence number.
Definition: icmpv4.cc:146
Base class for all the ICMP packet headers.
Definition: icmpv4.h:41
@ ICMPV4_TIME_EXCEEDED
Definition: icmpv4.h:51
void SetCode(uint8_t code)
Set ICMP code.
Definition: icmpv4.cc:115
void SetType(uint8_t type)
Set ICMP type.
Definition: icmpv4.cc:109
uint8_t GetType(void) const
Get ICMP type.
Definition: icmpv4.cc:121
void EnableChecksum(void)
Enables ICMP Checksum calculation.
Definition: icmpv4.cc:57
static const uint8_t PROT_NUMBER
ICMP protocol number (0x1)
ICMP Time Exceeded header.
Definition: icmpv4.h:247
void GetData(uint8_t payload[8]) const
Get the ICMP carried data.
Definition: icmpv4.cc:438
an Inet address class
uint16_t GetPort(void) const
Ipv4Address GetIpv4(void) const
static bool IsMatchingType(const Address &address)
static InetSocketAddress ConvertFrom(const Address &address)
Returns an InetSocketAddress which corresponds to the input Address.
static Ipv4Address GetAny(void)
AttributeValue implementation for Ipv4Address.
Definition: ipv4-address.h:341
Packet header for IPv4.
Definition: ipv4-header.h:34
uint8_t GetProtocol(void) const
Definition: ipv4-header.cc:272
static bool ChecksumEnabled(void)
Definition: node.cc:278
uint32_t GetNApplications(void) const
Definition: node.cc:178
Ptr< Application > GetApplication(uint32_t index) const
Retrieve the index-th Application associated to this node.
Definition: node.cc:170
void SetAttribute(std::string name, const AttributeValue &value)
Set a single attribute, raising fatal errors if unsuccessful.
Definition: object-base.cc:256
std::ostream * GetStream(void)
Return a pointer to an ostream previously set in the wrapper.
uint32_t RemoveHeader(Header &header)
Deserialize and remove the header from the internal buffer.
Definition: packet.cc:280
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:256
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:856
static EventId Schedule(Time const &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:556
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition: simulator.h:587
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:195
virtual void SetIpTtl(uint8_t ipTtl)
Manually set IP Time to Live field.
Definition: socket.cc:513
virtual int Close(void)=0
Close a socket.
void SetRecvCallback(Callback< void, Ptr< Socket > > receivedData)
Notify application when new data is available to be read.
Definition: socket.cc:128
virtual uint32_t GetRxAvailable(void) const =0
Return number of bytes which can be returned from one or multiple calls to Recv.
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:71
virtual int Bind(const Address &address)=0
Allocate a local endpoint for this socket.
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 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:103
@ MS
millisecond
Definition: nstime.h:115
TimeWithUnit As(const enum Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition: time.cc:418
AttributeValue implementation for Time.
Definition: nstime.h:1308
a unique identifier for an interface.
Definition: type-id.h:59
static TypeId LookupByName(std::string name)
Get a TypeId by name.
Definition: type-id.cc:829
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:922
Hold an unsigned integer type.
Definition: uinteger.h:44
Traceroute application sends one ICMP ECHO request with TTL=1, and after receiving an ICMP TIME EXCEE...
Definition: v4traceroute.h:51
Ipv4Address m_remote
Remote address.
Definition: v4traceroute.h:95
void HandleWaitReplyTimeout()
Triggers an action if an ICMP TIME EXCEED have not being received in the time defined by StartWaitRep...
virtual void StopApplication(void)
Application specific shutdown code.
uint32_t GetApplicationId(void) const
Return the application ID in the node.
EventId m_next
Next packet will be sent.
Definition: v4traceroute.h:114
std::ostringstream m_routeIpv4
The Ipv4 address of the latest hop found.
Definition: v4traceroute.h:133
Ptr< OutputStreamWrapper > m_printStream
Stream of the traceroute used for the output file.
Definition: v4traceroute.h:135
uint32_t m_probeCount
The Current probe value.
Definition: v4traceroute.h:116
static TypeId GetTypeId(void)
Get the type ID.
Definition: v4traceroute.cc:47
uint16_t m_seq
ICMP ECHO sequence number.
Definition: v4traceroute.h:108
virtual void DoDispose(void)
Destructor implementation.
uint16_t m_ttl
The current TTL value.
Definition: v4traceroute.h:120
std::map< uint16_t, Time > m_sent
All sent but not answered packets. Map icmp seqno -> when sent.
Definition: v4traceroute.h:128
Ptr< Socket > m_socket
The socket we send packets from.
Definition: v4traceroute.h:106
uint32_t m_maxTtl
The maximium Ttl (Max number of hops to trace)
Definition: v4traceroute.h:122
Time m_interval
Wait interval seconds between sending each packet.
Definition: v4traceroute.h:98
void Print(Ptr< OutputStreamWrapper > stream)
Prints the application traced routes into a given OutputStream.
virtual ~V4TraceRoute()
std::ostringstream m_osRoute
Stream of characters used for printing a single route.
Definition: v4traceroute.h:131
virtual void StartApplication(void)
Application specific startup code.
Time m_started
Start time to report total ping time.
Definition: v4traceroute.h:112
EventId m_waitIcmpReplyTimer
The timer used to wait for the probes ICMP replies.
Definition: v4traceroute.h:126
uint32_t m_size
Specifies the number of data bytes to be sent.
Definition: v4traceroute.h:104
uint16_t m_maxProbes
The maximum number of probe packets per hop.
Definition: v4traceroute.h:118
Time m_waitIcmpReplyTimeout
The wait time until the response is considered lost.
Definition: v4traceroute.h:124
void Receive(Ptr< Socket > socket)
Receive an ICMP Echo.
void StartWaitReplyTimer()
Starts a timer after sending an ICMP ECHO.
bool m_verbose
produce traceroute style output if true
Definition: v4traceroute.h:110
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:67
#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:88
Ptr< const AttributeChecker > MakeBooleanChecker(void)
Definition: boolean.cc:121
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:85
Ptr< const AttributeChecker > MakeIpv4AddressChecker(void)
Ptr< const AttributeAccessor > MakeIpv4AddressAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: ipv4-address.h:341
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:1309
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:45
#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:205
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:289
#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:281
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1244
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:522
Callback< R, Ts... > MakeCallback(R(T::*memPtr)(Ts...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:1648
uint8_t data[writeSize]