I am writing a python script to perform 'TCP Traceroute'. I learned scapy is a useful library to do this but I`m not getting the results I need. Can anyone help me resolve this? I want the python script to generate similar results as command line.
I am using linux, python 2.7 with scapy 2.4. I am not sure why same ip addresses are shown for all the hops.
from scapy.layers.inet import traceroute
result, unans = traceroute('172.217.17.46', maxttl=30)
for snd, rcv in result:
print snd.ttl, rcv.src, snd.sent_time, rcv.time
When I run this code I get following results:
1 10.0.2.2 1541113255.58 1541113255.6
2 172.217.17.46 1541113255.58 1541113255.72
3 172.217.17.46 1541113255.58 1541113255.72
4 172.217.17.46 1541113255.58 1541113255.72
5 172.217.17.46 1541113255.59 1541113255.73
6 172.217.17.46 1541113255.59 1541113255.73
7 172.217.17.46 1541113255.6 1541113255.74
8 172.217.17.46 1541113255.6 1541113255.74
9 172.217.17.46 1541113255.6 1541113255.74
10 172.217.17.46 1541113255.61 1541113255.75
11 172.217.17.46 1541113255.61 1541113255.75
12 172.217.17.46 1541113255.61 1541113255.75
13 172.217.17.46 1541113255.62 1541113255.76
14 172.217.17.46 1541113255.62 1541113255.76
15 172.217.17.46 1541113255.62 1541113255.76
16 172.217.17.46 1541113255.62 1541113255.77
17 172.217.17.46 1541113255.63 1541113255.77
18 172.217.17.46 1541113255.63 1541113255.77
19 172.217.17.46 1541113255.63 1541113255.77
20 172.217.17.46 1541113255.63 1541113255.77
21 172.217.17.46 1541113255.64 1541113255.78
22 172.217.17.46 1541113255.64 1541113255.78
23 172.217.17.46 1541113255.64 1541113255.78
24 172.217.17.46 1541113255.64 1541113255.78
25 172.217.17.46 1541113255.65 1541113255.79
26 172.217.17.46 1541113255.65 1541113255.79
27 172.217.17.46 1541113255.65 1541113255.79
28 172.217.17.46 1541113255.66 1541113255.8
29 172.217.17.46 1541113255.66 1541113255.8
30 172.217.17.46 1541113255.66 1541113255.8
I want to get the same results which I get when I run tcptraceroute from command line: tcptraceroute 172.217.17.46
Result from command line:
Selected device en0, address 192.168.86.24, port 49618 for outgoing packets
Tracing the path to 172.217.17.46 on TCP port 80 (http), 30 hops max
1 192.168.86.1 2.848 ms 1.224 ms 1.330 ms
2 96.120.101.53 10.423 ms 13.646 ms 12.221 ms
3 po-115-rur102.bellevue.wa.seattle.comcast.net (68.87.205.245) 18.877 ms 18.818 ms 12.593 ms
4 be-103-ar01.seattle.wa.seattle.comcast.net (69.139.164.77) 15.188 ms 14.272 ms 14.005 ms
5 be-33650-cr01.seattle.wa.ibone.comcast.net (68.86.93.165) 14.547 ms 15.273 ms 19.750 ms
6 be-10846-pe01.seattle.wa.ibone.comcast.net (68.86.86.90) 14.546 ms 14.266 ms 13.521 ms
7 50.242.150.242 14.159 ms 15.791 ms 14.037 ms
8 74.125.243.195 14.635 ms 22.377 ms 13.558 ms
9 72.14.236.174 15.051 ms 27.454 ms 14.312 ms
10 108.170.235.60 66.430 ms 69.762 ms 68.606 ms
11 216.239.58.255 85.531 ms 84.354 ms 85.303 ms
12 172.253.51.157 153.310 ms 154.710 ms 153.375 ms
13 209.85.142.166 157.376 ms 166.552 ms 157.562 ms
14 216.239.43.37 170.523 ms 168.040 ms 158.182 ms
15 108.170.241.225 158.953 ms 161.418 ms 169.103 ms
16 108.170.236.137 158.561 ms 161.635 ms 157.510 ms
17 ams16s29-in-f46.1e100.net (172.217.17.46) [open] 165.981 ms 160.451 ms 166.120 ms
Question1: Is scapy traceroute function really does TCP traceroute? Question2: I am new to scapy and traceroute, Is there something obvious I am missing in the code? Is there any other library which I can use if scapy is not suitable? I would really appreciate the help and any pointers.
NOTE: I WANT TO PERFORM TCP TRACE ROUTE FOR BOTH IPV6 AND IPV4.
Though often misunderstood to mean the same thing, a Traceroute and a TCP Traceroute are fundamentally different operations. The main difference of that operation being that Traceroute uses ICMP packets while TCP Traceroute uses TCP packets.
The Trace TCP/IP Route (TRCTCPRTE) command, also known as TRACEROUTE, traces the route of IP packets to a user-specified destination system. The route can involve many different systems along the way. Each system along the route is referred to as a hop.
It is based on the "half-open scanning" technique that is used by NMAP, sending a TCP with the SYN flag set and waiting for a SYN/ACK (which indicates that something is listening on this port for connections). When it receives a response, the tcptraceroute program sends a packet with a RST flag to close the connection.
The regular traceroute usually uses either ICMP or UDP protocols. Unfortunately firewalls and routers often block the ICMP protocol completely or disallow the ICMP echo requests (ping requests), and/or block various UDP ports.
Is scapy
traceroute function really does TCP traceroute?
Yes it does do TCP
traceroute (among other things). Take a look at Scapy
source-code:
@conf.commands.register def traceroute(target, dport=80, minttl=1, maxttl=30, sport=RandShort(), l4 = None, filter=None, timeout=2, verbose=None, **kargs): """Instant TCP traceroute traceroute(target, [maxttl=30,] [dport=80,] [sport=80,] [verbose=conf.verb]) -> None""" if verbose is None: verbose = conf.verb if filter is None: # we only consider ICMP error packets and TCP packets with at # least the ACK flag set *and* either the SYN or the RST flag # set filter="(icmp and (icmp[0]=3 or icmp[0]=4 or icmp[0]=5 or icmp[0]=11 or icmp[0]=12)) or (tcp and (tcp[13] & 0x16 > 0x10))" if l4 is None: a,b = sr(IP(dst=target, id=RandShort(), ttl=(minttl,maxttl))/TCP(seq=RandInt(),sport=sport, dport=dport), timeout=timeout, filter=filter, verbose=verbose, **kargs) else: # this should always work filter="ip" a,b = sr(IP(dst=target, id=RandShort(), ttl=(minttl,maxttl))/l4, timeout=timeout, filter=filter, verbose=verbose, **kargs) a = TracerouteResult(a.res) if verbose: a.show() return a,b
def traceroute6(target, dport=80, minttl=1, maxttl=30, sport=RandShort(), l4 = None, timeout=2, verbose=None, **kargs): """ Instant TCP traceroute using IPv6 : traceroute6(target, [maxttl=30], [dport=80], [sport=80]) -> None """ if verbose is None: verbose = conf.verb if l4 is None: a,b = sr(IPv6(dst=target, hlim=(minttl,maxttl))/TCP(seq=RandInt(),sport=sport, dport=dport), timeout=timeout, filter="icmp6 or tcp", verbose=verbose, **kargs) else: a,b = sr(IPv6(dst=target, hlim=(minttl,maxttl))/l4, timeout=timeout, verbose=verbose, **kargs) a = TracerouteResult6(a.res) if verbose: a.display() return a,b
The following example code is for traceroute ipv6. On Windows platforms, Npcap must be installed.
from scapy.all import * waypoint = "2001:301:0:8002:203:47ff:fea5:3085" target = "2001:5f9:4:7:2e0:81ff:fe52:9a6b" traceroute6(waypoint, minttl=10, maxttl=40, l4=IPv6ExtHdrRouting(addresses=[target])/ICMPv6EchoRequest(data=RandString(7)))
Using a DNS traceroute
by specifying a complete packet in the l4 parameter of traceroute() function you don't get same IP addresses for all the hops.
from scapy.all import * target = ["172.217.17.46"] result, unans = traceroute(target, l4=UDP(sport=RandShort())/DNS(qd=DNSQR(qname="www.google.com")))
from scapy.all import * target = ["172.217.17.46"] result, unans = sr(IP(dst=target, ttl=(1, 10)) / TCP(dport=53, flags="S")) for snd, rcv in result: print(snd.ttl, rcv.src, snd.sent_time, rcv.time)
from scapy.all import * hostname = "172.217.17.46" for i in range(1, 28): pkt = IP(dst=hostname, ttl=i) / UDP(dport=33434) reply = sr1(pkt, verbose=0) if reply is None: break elif reply.type == 3: print("Done!", reply.src) break else: print("%d hops away: " % i, reply.src, reply.time)
import webb webb.traceroute("www.google.com") webb.traceroute("www.google.com",'file-name.txt')
Also, check out this tcptraceroute
by Thomas Guettler.
Or this Multi-source traceroute with geolocation implementation by Addy Yeow (Ayeowch).
Among other things, using -j
parameter (JSON_FILE), it will list sources in JSON file format.
Or this implementation by Christian Kreibich. It can parse traceroute info into a series of hop objects, each consisting of one or more probe results, likewise, object instances. Also, string formatting produces familiar traceroute output.
(In order to work with Python 3
one needs to change cStringIO
to from io import StringIO
Without scapy
(using windows console):
Create a script named
output.py
containing the following:
import sys
from subprocess import Popen
if len(sys.argv) < 2:
print('Usage: output.py "command to watch"')
sys.exit(1)
cmd_line = sys.argv[1:]
p = Popen(cmd_line)
p.communicate()[0]
Example usage: python output.py ping google.com
Example output for
ping
:
Pinging google.com [216.58.209.14] with 32 bytes of data: Reply from 216.58.209.14: bytes=32 time=50ms TTL=56 Reply from 216.58.209.14: bytes=32 time=45ms TTL=56 Reply from 216.58.209.14: bytes=32 time=45ms TTL=56 Reply from 216.58.209.14: bytes=32 time=45ms TTL=56 Ping statistics for 216.58.209.14: Packets: Sent = 4, Received = 4, Lost = 0 (0% loss), Approximate round trip times in milli-seconds: Minimum = 45ms, Maximum = 50ms, Average = 46ms
Example usage: python output.py tracert google.com
Example output for
tracert
:Tracing route to google.com [172.217.18.174] over a maximum of 30 hops: 1 <1 ms 1 ms 1 ms 192.168.0.1 2 6 ms 8 ms 8 ms xx.xx.xx.xx 3 8 ms 8 ms 8 ms [xx.xx.xxx.xxx] 4 17 ms 16 ms 16 ms be3549.ccr31.sof02.atlas.cogentco.com [154.54.59.138] 5 18 ms 17 ms 20 ms be3421.ccr51.beg03.atlas.cogentco.com [130.117.0.94] 6 32 ms 31 ms 30 ms be3464.ccr52.vie01.atlas.cogentco.com [154.54.59.189] 7 39 ms 37 ms 44 ms be3462.ccr22.muc03.atlas.cogentco.com [154.54.59.182] 8 42 ms 48 ms 44 ms be2960.ccr42.fra03.atlas.cogentco.com [154.54.36.253] 9 44 ms 50 ms 50 ms be3187.agr41.fra03.atlas.cogentco.com [130.117.1.117] 10 43 ms 45 ms 46 ms tata.fra03.atlas.cogentco.com [130.117.15.86] 11 45 ms 45 ms 44 ms 72.14.196.162 12 43 ms 41 ms 46 ms 108.170.251.129 13 46 ms 46 ms 45 ms 74.125.37.167 14 45 ms 52 ms 48 ms fra15s29-in-f14.1e100.net [172.217.18.174]
You can use tracert -d
if you don't want names to be resolved.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With