Created
July 30, 2021 11:59
-
-
Save usr-ein/0172ca51ee1b668646fa1fd141d990ed to your computer and use it in GitHub Desktop.
Traceroute mapping - maps hops that packet make by setting the TTL to increasing values and seeing where it dies, then making a geo map from the IPs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# CLI | |
import sys | |
# Traceroute | |
import pexpect | |
# import trparse # DEPRECATED | |
import socket | |
import struct | |
# IP location | |
import json | |
import urllib.request | |
# View | |
import numpy as np | |
from mpl_toolkits.basemap import Basemap | |
import matplotlib.pyplot as pl | |
import matplotlib.lines as mlines | |
# This function was not wrote by me, just slightly modified to suit my purposes | |
# (form https://securityblog.gr/1047/simple-python-traceroute/) | |
def customTraceroute(hostname, port=80, max_hops=32, timeout=15): | |
destination = socket.gethostbyname(hostname) | |
ttl = 1 | |
listTracerouteHops = [] | |
while True: | |
recvsock = socket.socket(family=socket.AF_INET, | |
type=socket.SOCK_RAW, | |
proto=socket.IPPROTO_ICMP) | |
recvsock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, struct.pack("ll", timeout, 0)) | |
recvsock.bind(("", port)) | |
sendsock = socket.socket(family=socket.AF_INET, | |
type=socket.SOCK_DGRAM, | |
proto=socket.IPPROTO_UDP) | |
sendsock.setsockopt(socket.SOL_IP, socket.IP_TTL, ttl) | |
sendsock.sendto(bytearray(), (hostname, port)) | |
currentaddr = None | |
try: | |
# _, currentaddr = recvsock.recvfrom(512) | |
data, addr = recvsock.recvfrom(1024) | |
currentaddr = addr[0] | |
except socket.error as err: | |
if err.errno == 35: # [Errno 35] Resource temporarily unavailable (timeout) | |
return listTracerouteHops | |
pass | |
finally: | |
sendsock.close() | |
recvsock.close() | |
if currentaddr is not None: | |
listTracerouteHops.append(currentaddr) | |
# print("Hop N°{} — {}".format(ttl, currentaddr)) # debug | |
ttl += 1 | |
if currentaddr == destination or ttl > max_hops: | |
break | |
print("End traceroute") | |
return listTracerouteHops | |
def getLatLonFromIP(ipList): | |
latLonIPList = [] | |
for ip in ipList: | |
if len(latLonIPList) > 0: | |
if (latLonIPList[len(latLonIPList)-1])[2] == ip: | |
# if we're checking the same ip as before, don't proceed, don't flood the API | |
continue | |
with urllib.request.urlopen("http://ip-api.com/json/{}".format(ip)) as res: | |
jsonRes = res.read() | |
objRes = json.loads(jsonRes) | |
if objRes['status'] != "success": | |
# if we did not succeeded, then we shall skip this ip | |
continue | |
latLonIP = [] | |
latLonIP.append(objRes['lat']) # 0 | |
latLonIP.append(objRes['lon']) # 1 | |
latLonIP.append(ip) # 2 | |
latLonIPList.append(latLonIP) | |
print(latLonIPList) | |
return latLonIPList | |
def plotAndDisplay(latLonIPList): | |
fig = pl.figure(figsize=(12,12)) | |
fig.set_size_inches((12,12)) | |
# Plot a map for Paris (using lat/long) | |
# m = Basemap(projection='merc', llcrnrlat=48.783, urcrnrlat=48.916,llcrnrlon=2.216, urcrnrlon=2.483, resolution='h', area_thresh=0.1) | |
# m = Basemap(projection='merc', llcrnrlat=47.811079, urcrnrlat=49.765078,llcrnrlon=0.357056, urcrnrlon=4.663696, resolution='i', area_thresh=0.1) | |
# Plot a map of the World | |
m = Basemap(projection='cyl', llcrnrlat=-90, urcrnrlat=90, llcrnrlon=-180, urcrnrlon=180, resolution='l') | |
m.bluemarble() | |
m.drawcoastlines(linewidth=0.5) | |
# m.drawcountries(linewidth=0.5) | |
# m.drawstates(linewidth=0.5) | |
m.drawmapboundary(fill_color='aqua') | |
for latLonIP in latLonIPList: | |
latitude = float(latLonIP[0]) | |
longitude = float(latLonIP[1]) | |
ip = latLonIP[2] | |
#Convert latitude and longitude to coordinates X and Y | |
x, y = m(longitude, latitude) | |
pl.plot(x, y, 'bo', markersize=3, color='red', linewidth=20.0) | |
pl.text(x+10000, y+10000, ip) | |
index = latLonIPList.index(latLonIP) | |
if index+1 < len(latLonIPList): | |
nextLatLonIP = latLonIPList[index+1] | |
nextLatitude = float(nextLatLonIP[0]) | |
nextLongitude = float(nextLatLonIP[1]) | |
n_x, n_y = m(nextLongitude, nextLatitude) | |
if x != n_x and y != n_y: | |
newArrow([x,y],[n_x,n_y]) | |
# pl.ion() | |
# lg = pl.legend() | |
# lg.get_frame().set_facecolor('grey') | |
pl.show() | |
def newArrow(p1, p2): | |
# ax = pl.axes() | |
# ax.arrow(p1[0], p2[0], p1[1], p2[1], head_width=0.05, head_length=0.1, fc='k', ec='k') | |
pl.arrow(p1[0],p1[1],p2[0]-p1[0],p2[1]-p1[1],fc="k", ec="k", linewidth = 1, head_width=0.5, head_length=0.5) | |
def newSegment(p1, p2): | |
ax = pl.gca() | |
l = mlines.Line2D([p1[0],p2[0]],[p1[1],p2[1]]) | |
ax.add_line(l) | |
return l | |
def newLine(p1, p2): | |
ax = pl.gca() | |
xmin, xmax = ax.get_xbound() | |
if(p2[0] == p1[0]): | |
xmin = xmax = p1[0] | |
ymin, ymax = ax.get_ybound() | |
else: | |
ymax = p1[1]+(p2[1]-p1[1])/(p2[0]-p1[0])*(xmax-p1[0]) | |
ymin = p1[1]+(p2[1]-p1[1])/(p2[0]-p1[0])*(xmin-p1[0]) | |
l = mlines.Line2D([xmin,xmax], [ymin,ymax]) | |
ax.add_line(l) | |
return l | |
if len(sys.argv) < 2: | |
exit("Please provide a domaine name to traceroute to:\nExample:\n\ttracerouteMap.py www.nicovideo.jp") | |
# "www.nicovideo.jp" | |
print(sys.argv[1]) | |
ipList = customTraceroute(sys.argv[1]) | |
print(ipList) | |
latLonIPList = getLatLonFromIP(ipList) | |
# latLonIPList = [[48.8713, 2.32143, '194.149.162.5'], [48.8713, 2.32143, '194.149.162.29'], [48.8238, 2.37669, '78.254.249.129'], [48.8713, 2.32143, '194.149.162.86'], [50.5878, 2.5183, '149.11.115.13'], [52.5167, 13.4, '130.117.15.70'], [52.4833, -0.6667, '80.231.153.50'], [43.2965, 5.36978, '80.231.217.5'], [43.2965, 5.36978, '80.231.217.107'], [-33.9249, 18.4241, '41.206.178.30']] | |
# latLonIPList = [[43.5513, 7.0128, '80.236.8.169'], [43.5513, 7.0128, '80.236.8.185'], [51.4, 0.05, '94.31.32.137'], [39.9469, -105.2142, '64.125.29.4'], [39.9469, -105.2142, '64.125.29.84'], [39.9469, -105.2142, '64.125.29.25'], [39.9469, -105.2142, '64.125.30.237'], [39.9469, -105.2142, '64.125.30.53'], [53.9667, -1.0833, '195.66.226.145'], [37.3042, -122.0946, '17.0.90.78'], [37.3042, -122.0946, '17.0.161.96'], [37.3042, -122.0946, '17.0.90.78'], [37.3042, -122.0946, '17.0.146.114'], [37.3042, -122.0946, '17.0.90.69'], [37.3042, -122.0946, '17.0.146.114'], [37.3042, -122.0946, '17.1.0.114'], [37.3042, -122.0946, '17.1.0.113'], [37.3042, -122.0946, '17.0.78.69'], [37.3042, -122.0946, '17.0.133.72'], [37.3042, -122.0946, '17.0.95.70'], [37.3042, -122.0946, '17.0.95.51'], [37.3042, -122.0946, '17.0.95.49'], [37.3042, -122.0946, '17.0.95.53']] | |
plotAndDisplay(latLonIPList) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment