A Discrete-Event Network Simulator
API
v4traceroute.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019 Ritsumeikan University, Shiga, Japan
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Alberto Gallegos Ramonet
18  *
19  * Traceroute uses ICMPV4 echo messages to trace all the middle hops to a given destination.
20  * It also shows the delay time it takes for a round trip to complete for each
21  * set probe (default 3).
22  *
23  */
24 
25 #include "v4traceroute.h"
26 
27 #include "ns3/assert.h"
28 #include "ns3/boolean.h"
29 #include "ns3/icmpv4-l4-protocol.h"
30 #include "ns3/icmpv4.h"
31 #include "ns3/inet-socket-address.h"
32 #include "ns3/ipv4-address.h"
33 #include "ns3/log.h"
34 #include "ns3/packet.h"
35 #include "ns3/socket.h"
36 #include "ns3/trace-source-accessor.h"
37 #include "ns3/uinteger.h"
38 
39 namespace ns3
40 {
41 
42 NS_LOG_COMPONENT_DEFINE("V4TraceRoute");
43 NS_OBJECT_ENSURE_REGISTERED(V4TraceRoute);
44 
45 TypeId
47 {
48  static TypeId tid = TypeId("ns3::V4TraceRoute")
50  .SetGroupName("Internet-Apps")
51  .AddConstructor<V4TraceRoute>()
52  .AddAttribute("Remote",
53  "The address of the machine we want to trace.",
54  Ipv4AddressValue(),
55  MakeIpv4AddressAccessor(&V4TraceRoute::m_remote),
56  MakeIpv4AddressChecker())
57  .AddAttribute("Verbose",
58  "Produce usual output.",
59  BooleanValue(true),
62  .AddAttribute("Interval",
63  "Wait interval between sent packets.",
64  TimeValue(Seconds(0)),
67  .AddAttribute("Size",
68  "The number of data bytes to be sent, real packet will "
69  "be 8 (ICMP) + 20 (IP) bytes longer.",
70  UintegerValue(56),
72  MakeUintegerChecker<uint32_t>())
73  .AddAttribute("MaxHop",
74  "The maximum number of hops to trace.",
75  UintegerValue(30),
77  MakeUintegerChecker<uint32_t>())
78  .AddAttribute("ProbeNum",
79  "The number of packets send to each hop.",
80  UintegerValue(3),
82  MakeUintegerChecker<uint16_t>())
83  .AddAttribute("Timeout",
84  "The waiting time for a route response before a timeout.",
85  TimeValue(Seconds(5)),
87  MakeTimeChecker());
88  return tid;
89 }
90 
92  : m_interval(Seconds(0)),
93  m_size(56),
94  m_socket(nullptr),
95  m_seq(0),
96  m_verbose(true),
97  m_probeCount(0),
98  m_maxProbes(3),
99  m_ttl(1),
100  m_maxTtl(30),
101  m_waitIcmpReplyTimeout(Seconds(5))
102 {
103  m_osRoute.clear();
104  m_routeIpv4.clear();
105 }
106 
108 {
109 }
110 
111 void
113 {
114  m_printStream = stream;
115 }
116 
117 void
119 {
120  NS_LOG_FUNCTION(this);
121  NS_LOG_LOGIC("Application started");
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"));
138 
141 
143  int status;
144  status = m_socket->Bind(src);
145  NS_ASSERT(status != -1);
146 
148 }
149 
150 void
152 {
153  NS_LOG_FUNCTION(this);
154 
155  if (m_next.IsRunning())
156  {
157  m_next.Cancel();
158  }
159 
161  {
163  }
164 
165  if (m_socket)
166  {
167  m_socket->Close();
168  }
169 
170  if (m_verbose)
171  {
172  NS_LOG_UNCOND("\nTrace Complete");
173  }
174 
175  if (m_printStream)
176  {
177  *m_printStream->GetStream() << "Trace Complete\n" << std::endl;
178  }
179 }
180 
181 void
183 {
184  NS_LOG_FUNCTION(this);
185 
187  {
188  StopApplication();
189  }
190 
191  m_socket = nullptr;
193 }
194 
195 uint32_t
197 {
198  NS_LOG_FUNCTION(this);
199  Ptr<Node> node = GetNode();
200  for (uint32_t i = 0; i < node->GetNApplications(); ++i)
201  {
202  if (node->GetApplication(i) == this)
203  {
204  return i;
205  }
206  }
207  NS_ASSERT_MSG(false, "forgot to add application to node");
208  return 0;
209 }
210 
211 void
213 {
214  NS_LOG_FUNCTION(this << socket);
215 
216  while (m_socket->GetRxAvailable() > 0)
217  {
218  Address from;
219  Ptr<Packet> p = m_socket->RecvFrom(0xffffffff, 0, from);
220  NS_LOG_DEBUG("recv " << p->GetSize() << " bytes");
223  NS_ASSERT(realFrom.GetPort() == 1);
225  p->RemoveHeader(ipv4);
226  NS_ASSERT(ipv4.GetProtocol() == Icmpv4L4Protocol::PROT_NUMBER);
227  Icmpv4Header icmp;
228  p->RemoveHeader(icmp);
229 
231  {
232  Icmpv4TimeExceeded timeoutResp;
233  p->RemoveHeader(timeoutResp);
234 
235  // GetData () gets 64 bits of data, but the received packet
236  // only contains 32 bits of data.
237  uint8_t data[8];
238  timeoutResp.GetData(data);
239 
240  // Get the 7th and 8th Octet to obtain the Sequence number from
241  // the original packet.
242  uint16_t recvSeq;
243  recvSeq = (uint16_t)data[7] << 0;
244  recvSeq |= (uint16_t)data[6] << 8;
245 
246  auto 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)
265  {
267  << m_ttl << " " << m_routeIpv4.str() << " " << m_osRoute.str() << "\n";
268  }
269  m_osRoute.str("");
270  m_osRoute.clear();
271  m_routeIpv4.str("");
272  m_routeIpv4.clear();
273  }
274  else
275  {
276  m_osRoute << " ";
277  }
278 
280 
281  if (m_ttl < m_maxTtl + 1)
282  {
283  m_next =
285  }
286  }
287  }
288  else if (icmp.GetType() == Icmpv4Header::ICMPV4_ECHO_REPLY &&
289  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  auto 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() << " "
323  << m_osRoute.str());
324  if (m_printStream)
325  {
326  *m_printStream->GetStream() << m_ttl << " " << 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)
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 void
365 {
366  NS_LOG_INFO("m_seq=" << m_seq);
367  Ptr<Packet> p = Create<Packet>();
368  Icmpv4Echo echo;
369  echo.SetSequenceNumber(m_seq);
370  m_seq++;
371  echo.SetIdentifier(0);
372 
373  //
374  // We must write quantities out in some form of network order. Since there
375  // isn't an htonl to work with we just follow the convention in pcap traces
376  // (where any difference would show up anyway) and borrow that code. Don't
377  // be too surprised when you see that this is a little endian convention.
378  //
379  NS_ASSERT(m_size >= 16);
380 
381  Ptr<Packet> dataPacket = Create<Packet>(m_size);
382  echo.SetData(dataPacket);
383  p->AddHeader(echo);
384  Icmpv4Header header;
386  header.SetCode(0);
387  if (Node::ChecksumEnabled())
388  {
389  header.EnableChecksum();
390  }
391 
392  p->AddHeader(header);
393 
395  {
396  m_probeCount++;
397  }
398  else
399  {
400  m_probeCount = 1;
401  m_ttl++;
402  }
403 
404  m_sent.insert(std::make_pair(m_seq - 1, Simulator::Now()));
406 
408  m_socket->SendTo(p, 0, dst);
409 }
410 
411 void
413 {
414  NS_LOG_FUNCTION(this);
416  {
417  NS_LOG_LOGIC("Starting WaitIcmpReplyTimer at " << Simulator::Now() << " for "
419 
422  this);
423  Send();
424  }
425 }
426 
427 void
429 {
430  if (m_ttl < m_maxTtl + 1)
431  {
433  }
434 
435  m_osRoute << "* ";
436  if (m_probeCount == m_maxProbes)
437  {
438  if (m_verbose)
439  {
440  NS_LOG_UNCOND(m_ttl << " " << m_routeIpv4.str() << " " << m_osRoute.str());
441  }
442 
443  if (m_printStream)
444  {
446  << m_ttl << " " << m_routeIpv4.str() << " " << m_osRoute.str() << "\n";
447  }
448  m_osRoute.str("");
449  m_osRoute.clear();
450  m_routeIpv4.str("");
451  m_routeIpv4.clear();
452  }
453 }
454 
455 } // namespace ns3
a polymophic address class
Definition: address.h:101
The base class for all ns3 applications.
Definition: application.h:62
void DoDispose() override
Destructor implementation.
Definition: application.cc:86
Ptr< Node > GetNode() const
Definition: application.cc:108
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition: event-id.cc:55
bool IsRunning() const
This method is syntactic sugar for !IsExpired().
Definition: event-id.cc:76
ICMP Echo header.
Definition: icmpv4.h:110
void SetIdentifier(uint16_t id)
Set the Echo identifier.
Definition: icmpv4.cc:150
void SetData(Ptr< const Packet > data)
Set the Echo data.
Definition: icmpv4.cc:164
uint16_t GetIdentifier() const
Get the Echo identifier.
Definition: icmpv4.cc:186
void SetSequenceNumber(uint16_t seq)
Set the Echo sequence number.
Definition: icmpv4.cc:157
uint32_t GetDataSize() const
Get the Echo data size.
Definition: icmpv4.cc:200
uint16_t GetSequenceNumber() const
Get the Echo sequence number.
Definition: icmpv4.cc:193
Base class for all the ICMP packet headers.
Definition: icmpv4.h:43
@ ICMPV4_TIME_EXCEEDED
Definition: icmpv4.h:53
void SetCode(uint8_t code)
Set ICMP code.
Definition: icmpv4.cc:123
void SetType(uint8_t type)
Set ICMP type.
Definition: icmpv4.cc:116
void EnableChecksum()
Enables ICMP Checksum calculation.
Definition: icmpv4.cc:60
uint8_t GetType() const
Get ICMP type.
Definition: icmpv4.cc:130
static const uint8_t PROT_NUMBER
ICMP protocol number (0x1)
ICMP Time Exceeded header.
Definition: icmpv4.h:250
void GetData(uint8_t payload[8]) const
Get the ICMP carried data.
Definition: icmpv4.cc:469
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:34
uint32_t GetNApplications() const
Definition: node.cc:190
Ptr< Application > GetApplication(uint32_t index) const
Retrieve the index-th Application associated to this node.
Definition: node.cc:180
static bool ChecksumEnabled()
Definition: node.cc:285
void SetAttribute(std::string name, const AttributeValue &value)
Set a single attribute, raising fatal errors if unsuccessful.
Definition: object-base.cc:204
std::ostream * GetStream()
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:294
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:268
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:861
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition: simulator.h:605
virtual void SetIpTtl(uint8_t ipTtl)
Manually set IP Time to Live field.
Definition: socket.cc:510
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:128
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:72
virtual int Close()=0
Close a socket.
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:105
@ MS
millisecond
Definition: nstime.h:117
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:835
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
Hold an unsigned integer type.
Definition: uinteger.h:45
Traceroute application sends one ICMP ECHO request with TTL=1, and after receiving an ICMP TIME EXCEE...
Definition: v4traceroute.h:51
~V4TraceRoute() override
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...
void StopApplication() override
Application specific shutdown code.
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
void StartApplication() override
Application specific startup code.
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
uint16_t m_seq
ICMP ECHO sequence number.
Definition: v4traceroute.h:108
uint32_t GetApplicationId() const
Return the application ID in the node.
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
void DoDispose() override
Destructor implementation.
Ptr< Socket > m_socket
The socket we send packets from.
Definition: v4traceroute.h:106
uint32_t m_maxTtl
The maximum 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.
std::ostringstream m_osRoute
Stream of characters used for printing a single route.
Definition: v4traceroute.h:131
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.
static TypeId GetTypeId()
Get the type ID.
Definition: v4traceroute.cc:46
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:66
#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:86
#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:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#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:275
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1414
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:704
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:533
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition: boolean.h:86
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:46
uint8_t data[writeSize]