-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtrace.py
128 lines (97 loc) · 4.15 KB
/
trace.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import socket
import struct
import sys
import requests # external module
class Traceroute:
# constant for geolocation webservice
FREEGEOPIP_URL = 'http://freegeoip.net/json/'
def __init__(self, sysArgs, port=33434, max_hops=30, ttl=1):
self.dest_name = str(sysArgs[1])
self.port = port
self.max_hops = max_hops
self.ttl = ttl
self.curr_addr = None
self.curr_name = None
self.last_printed = [0, "", ""]
self.hop_number = 0
# returns an IP address given a domain name
def get_ip(self):
return socket.gethostbyname(self.dest_name)
# returns a protocol constant (given a string) that can be used by sockets
def getting_protocols(self, proto1, proto2):
return socket.getprotobyname(proto1), socket.getprotobyname(proto2)
# return two sockets - receiving and sending
def create_sockets(self):
return socket.socket(socket.AF_INET, socket.SOCK_RAW, self.icmp), socket.socket(socket.AF_INET,
socket.SOCK_DGRAM, self.udp)
def set_sockets(self):
self.send_socket.setsockopt(socket.SOL_IP, socket.IP_TTL, self.ttl)
self.recv_socket.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, self.timeout)
self.recv_socket.bind(("", self.port))
self.send_socket.sendto("", (self.dest_name, self.port))
# getting hostname given an IP address
def get_hostname(self):
# trying to get the hostname
try:
self.curr_name = socket.gethostbyaddr(self.curr_addr)[0]
except socket.error:
self.curr_name = self.curr_addr
def close_sockets(self):
self.send_socket.close()
self.recv_socket.close()
# printing <hop-number>, <hostname>, <ip-address>, <geolocation>
def print_curr_hop(self):
# manipulating prints
if self.curr_addr is not None and self.curr_addr != self.last_printed[2]:
self.hop_number += 1
to_print = [self.hop_number, self.curr_name, self.curr_addr, self.get_geolocation_for_ip(self.curr_addr)]
print to_print
self.last_printed = to_print
# get icmp and udp protocols
# run until max hops is reached or destination addr is reached
# it creates sockets (receiving and sending)
# it sets them
# it tries to get hostnames given IP addresses
# and finally it prints each hop if it is not printed yet
def trace(self):
self.dest_addr = self.get_ip()
self.icmp, self.udp = self.getting_protocols('icmp', 'udp')
self.timeout = struct.pack("ll", 5, 0)
#while self.ttl < 20:
while True:
self.recv_socket, self.send_socket = self.create_sockets()
self.set_sockets()
try:
# getting data from receiving socket
_, self.curr_addr = self.recv_socket.recvfrom(512)
# _ is the data and curr_addr is a tuple with ip address and port, we care only for the first one
self.curr_addr = self.curr_addr[0]
self.get_hostname()
except socket.error:
pass
finally:
self.close_sockets()
self.print_curr_hop()
self.ttl += 1
# when to stop
if self.curr_addr == self.dest_addr or self.ttl > self.max_hops:
break
# it will return either latitude and longitude
def get_geolocation_for_ip(self, ip):
url = '{}/{}'.format(self.FREEGEOPIP_URL, ip)
try:
response = requests.get(url)
if response.status_code == 200:
json_return = response.json()
return json_return['latitude'], json_return['longitude']
elif response.status_code == 403:
print '403 - forbidden error'
#sys.exit()
else:
print 'something went wrong while getting geolocation'
#sys.exit()
except requests.exceptions.ConnectionError:
print 'check network connection'
sys.exit()
x = Traceroute(sys.argv)
x.trace()