Skip to content

Instantly share code, notes, and snippets.

@usr-ein
Created July 30, 2021 11:59
Show Gist options
  • Save usr-ein/0172ca51ee1b668646fa1fd141d990ed to your computer and use it in GitHub Desktop.
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
# 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