-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsockets.py
More file actions
185 lines (147 loc) · 5.84 KB
/
Copy pathsockets.py
File metadata and controls
185 lines (147 loc) · 5.84 KB
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
from socket import *
from struct import *
from random import randint
import sys
import select
import time
import binascii
import os
import fcntl
import ctypes
class ifreq(ctypes.Structure):
_fields_ = [("ifr_ifrn", ctypes.c_char * 16),
("ifr_flags", ctypes.c_short)]
UDP_CODE = getprotobyname('udp')
assert UDP_CODE == IPPROTO_UDP, "UDP Protocol type mismatch!"
HOST = gethostbyname(gethostname())
def construct_ip_header(hostip, ttl, ipid):
'''
8 bits 8 bits 16 bits = 32 bits
|--------------------------------------------------------------|
| ver | ihl | ip_tos | ip_tot_len |
|--------------------------------------------------------------|
| ip_id | ip_frag_off |
|--------------------------------------------------------------|
| ip_ttl | ip_proto | ip_checksum |
|--------------------------------------------------------------|
| ip_source |
|--------------------------------------------------------------|
| ip_dest |
|--------------------------------------------------------------|
'''
source_ip = "129.22.59.79"
ip_ver = 4 #IPv4 baby -> 4 bits
ip_ihl = 5 #5 words, 20 bytes (no options) -> 4 bits
ip_tos = 0 #pretty sure this isn't really used much -> 8 bits
ip_tot_len = 0 # kernel will fill this in (<3)
ip_id = ipid #packet id -> 16 bits
ip_frag_off = 0 #fragmentation offset -> 16 bits
ip_ttl = ttl # reduced by one on each hop -> 8 bits
ip_proto = UDP_CODE #wooo! -> 8 bits
ip_checksum = 0 # kernel will fill this in (<3)
ip_source = inet_aton(source_ip) #convert x.x.x.x to 32-bit packed binary
ip_dest = inet_aton(hostip) #convert x.x.x.x to 32-bit packed binary
ip_ihlver = (ip_ver << 4) + ip_ihl #combine to get 8 bits
'''
! for network order (big endian)orig_udp_header
B for unsigned char -> 8 bits
H for unsigned short -> 16 bits
4s for 4 byte (32 bit) string
'''
ip_header = pack('!BBHHHBBH4s4s', ip_ihlver, ip_tos, ip_tot_len, ip_id, ip_frag_off, ip_ttl, ip_proto, ip_checksum, ip_source, ip_dest)
return ip_header
def construct_udp_header():
#everything is 16 bits
udp_source = 20591 #20591 # source port
udp_dest = 33433 # destination port
udp_len = 8 #length will just be header length (min 8 bytes) as we will be sending an empty payload
udp_checksum = 0
#! for network order (big endian)
udp_header = pack('!HHHH', udp_source, udp_dest, udp_len, udp_checksum)
return udp_header
def construct_udp_packet():
udp_header = construct_udp_header()
payload = '' #we don't actually care to send data
return udp_header + payload
def create_packet(hostip, ttl, ipid):
ip_header = construct_ip_header(hostip, ttl, ipid)
payload = construct_udp_packet()
return ip_header + payload
def validate_ip(orig_ip_header, hostip, ipid, ttl):
orig_len = orig_ip_header[2]
orig_id = orig_ip_header[3]
orig_proto = orig_ip_header[6]
orig_dest = inet_ntoa(orig_ip_header[9])
return (orig_len == 28 and orig_id == ipid and orig_proto == UDP_CODE
and orig_dest == hostip)
def validate_udp(orig_udp_header):
orig_source = orig_udp_header[0]
orig_dest = orig_udp_header[1]
orig_len = orig_udp_header[2]
return (orig_source == 20591 and orig_dest == 33433 and orig_len == 8)
def await_response(my_socket, hostip, ipid, ttl, time_sent, timeout):
time_left = timeout
time_start = time.time()
while True:
valid_icmp = False
valid_ip = False
time_before = time.time()
try:
rec_packet = my_socket.recv(5120)
except:
time_left = time_left - timeout
if time_left <= 0:
raise Exception
timediff = time.time() - time_before
unpacked_ip = unpack('!BBHHHBBH4s4s', rec_packet[0:20]) #0:20
prot = unpacked_ip[6]
addr = inet_ntoa(unpacked_ip[8])
assert prot == 1
icmp_header = unpack('!BBH', rec_packet[20:24]) #21:24
icmp_type = icmp_header[0]
icmp_code = icmp_header[1]
if (icmp_type == 11 and icmp_code == 0):
orig_ip_header = unpack('!BBHHHBBH4s4s', rec_packet[28:48]) #29-48
valid_icmp = True
if(valid_icmp and validate_ip(orig_ip_header, hostip, ipid, ttl)):
orig_udp_header = unpack('!HHHH', rec_packet[48:56]) #49:56
valid_ip = True
if(valid_icmp and valid_ip and validate_udp(orig_udp_header)):
#this is our packet!
return time.time() - time_sent, addr
time_left = time_left - timediff
if time_left <= 0:
raise Exception
def getNewTTL(ttl):
return ttl+1
def traceroute(send_socket, recv_socket, hostip, timeout):
ttl = 0
while True:
ttl = getNewTTL(ttl)
ipid = randint(1,6535)
packet = create_packet(hostip, ttl, ipid)
send_socket.sendto(packet, (hostip, 33433))
try:
response_time, addr = await_response(recv_socket, hostip, ipid, ttl,
time.time(), timeout)
response_time = round(response_time * 1000, 2)
print str(ttl) + ": " + str(addr) + " => " + str(response_time) + "ms"
except:
print str(ttl) + ": " "*"
if addr == hostip or ttl == 30:
break
if __name__ == '__main__':
send_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)
send_socket.setsockopt(IPPROTO_IP, IP_HDRINCL, 1)
timeout = 0.75
print "timeout is set to " + str(timeout) + " seconds per probe"
setdefaulttimeout(timeout)
recv_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)
hostname = 'www.google.com'
try:
hostip = gethostbyname(hostname)
except:
print "Could not resolve hostname"
sys.exit()
traceroute(send_socket, recv_socket, hostip, timeout)
print "Trace complete"