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 * 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
39namespace ns3
40{
41
42NS_LOG_COMPONENT_DEFINE("V4TraceRoute");
43NS_OBJECT_ENSURE_REGISTERED(V4TraceRoute);
44
45TypeId
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.",
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.",
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.",
82 MakeUintegerChecker<uint16_t>())
83 .AddAttribute("Timeout",
84 "The waiting time for a route response before a timeout.",
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
111void
113{
114 m_printStream = stream;
115}
116
117void
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
150void
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
181void
183{
184 NS_LOG_FUNCTION(this);
185
187 {
189 }
190
191 m_socket = nullptr;
193}
194
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
211void
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);
224 Ipv4Header ipv4;
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 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);
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 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
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
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
363void
365{
366 NS_LOG_INFO("m_seq=" << m_seq);
367 Ptr<Packet> p = Create<Packet>();
368 Icmpv4Echo echo;
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);
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
411void
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
427void
429{
430 if (m_ttl < m_maxTtl + 1)
431 {
433 }
434
435 m_osRoute << "* ";
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:100
The base class for all ns3 applications.
Definition: application.h:61
void DoDispose() override
Destructor implementation.
Definition: application.cc:85
Ptr< Node > GetNode() const
Definition: application.cc:107
AttributeValue implementation for Boolean.
Definition: boolean.h:37
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:109
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:42
@ ICMPV4_TIME_EXCEEDED
Definition: icmpv4.h:52
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:249
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()
AttributeValue implementation for Ipv4Address.
Packet header for IPv4.
Definition: ipv4-header.h:34
static bool ChecksumEnabled()
Definition: node.cc:290
void SetAttribute(std::string name, const AttributeValue &value)
Set a single attribute, raising fatal errors if unsuccessful.
Definition: object-base.cc:200
std::ostream * GetStream()
Return a pointer to an ostream previously set in the wrapper.
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:568
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:199
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition: simulator.h:606
virtual void SetIpTtl(uint8_t ipTtl)
Manually set IP Time to Live field.
Definition: socket.cc:508
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:126
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 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
AttributeValue implementation for Time.
Definition: nstime.h:1423
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:840
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:936
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
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition: boolean.h:86
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition: nstime.h:1444
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1424
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:46
#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:1336
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:702
uint8_t data[writeSize]