-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest2.py
More file actions
137 lines (123 loc) · 6.74 KB
/
test2.py
File metadata and controls
137 lines (123 loc) · 6.74 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
import urllib, socket, random, struct
from urlparse import urlparse
def announce_udp(tracker,payload,ip_table):
tracker = tracker.lower()
parsed = urlparse(tracker)
# Teporarly Change udp:// to http:// to get hostname and portnumbe
url = parsed.geturl()[3:]
url = "http" + url
hostname = urlparse(url).hostname
port = urlparse(url).port
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(8)
conn = (socket.gethostbyname(hostname), port)
#sock.bind((socket.gethostname(),s_port))
#Get connection ID
req, transaction_id = udp_create_connection_request()
#print binascii.hexlify(req)
#print conn
sock.sendto(req, conn);
buf = sock.recvfrom(2048)[0]
connection_id = udp_parse_connection_response(buf, transaction_id)
#Annoucing
s_port = sock.getsockname()[1] #get port number to which socket is connected
req, transaction_id = udp_create_announce_request(connection_id, payload,s_port)
sock.sendto(req, conn)
print "\nAnnounce Request Sent"
buf = sock.recvfrom(2048)[0]
print "Response received"
return udp_parse_announce_response(buf, transaction_id,ip_table)
def udp_create_announce_request(connection_id, payload, s_port):
action = 0x1 #action (1 = announce)
transaction_id = udp_get_transaction_id()
print "2.Transaction ID :", transaction_id
#print (payload)
buf = struct.pack("!q", connection_id) #first 8 bytes is connection id
buf += struct.pack("!i", action) #next 4 bytes is action
buf += struct.pack("!i", transaction_id) #followed by 4 byte transaction id
buf += struct.pack("!20s", urllib.unquote(payload['info_hash'])) #the info hash of the torrent we announce ourselves in
buf += struct.pack("!20s", urllib.unquote(payload['peer_id'])) #the peer_id we announce
buf += struct.pack("!q", int(payload['downloaded'])) #number of bytes downloaded
buf += struct.pack("!q", int(payload['left'])) #number of bytes left
buf += struct.pack("!q", int(payload['uploaded'])) #number of bytes uploaded
buf += struct.pack("!i", 0x2) #event 2 denotes start of downloading
buf += struct.pack("!i", 0x0) #IP address set to 0. Response received to the sender of this packet
key = udp_get_transaction_id() #Unique key randomized by client
buf += struct.pack("!i", key)
buf += struct.pack("!i", -1) #Number of peers required. Set to -1 for default
buf += struct.pack("!i", s_port) #port on which response will be sent
return (buf, transaction_id)
def udp_parse_announce_response(buf, sent_transaction_id,ip_table):
#print "Response is:"+str(buf)
if len(buf) < 20:
raise RuntimeError("Wrong response length while announcing: %s" % len(buf))
action = struct.unpack_from("!i", buf)[0] #first 4 bytes is action
res_transaction_id = struct.unpack_from("!i", buf, 4)[0] #next 4 bytes is transaction id
if res_transaction_id != sent_transaction_id:
raise RuntimeError("Transaction ID doesnt match in announce response! Expected %s, got %s"
% (sent_transaction_id, res_transaction_id))
print "Reading Response\n"
if action == 0x1:
print "Action is 3"
ret = dict()
offset = 8; #next 4 bytes after action is transaction_id, so data doesnt start till byte 8
ret['interval'] = struct.unpack_from("!i", buf, offset)[0]
print "Interval:"+str(ret['interval'])
offset += 4
ret['leeches'] = struct.unpack_from("!i", buf, offset)[0]
print "Leeches:"+str(ret['leeches'])
offset += 4
ret['seeds'] = struct.unpack_from("!i", buf, offset)[0]
print "Seeds:"+str(ret['seeds'])
offset += 4
peers = list()
x = 0
print ""
while offset != len(buf):
peers.append(dict())
peers[x]['IP'] = struct.unpack_from("!i",buf,offset)[0]
if socket.inet_ntoa(struct.pack("!i",peers[x]['IP'])) not in ip_table:
ip_table.append(socket.inet_ntoa(struct.pack("!i",peers[x]['IP'])))
print x
print "IP: "+socket.inet_ntoa(struct.pack("!i",peers[x]['IP']))
offset += 4
if offset >= len(buf):
raise RuntimeError("Error while reading peer port")
peers[x]['port'] = struct.unpack_from("!H",buf,offset)[0]
print "Port: "+str(peers[x]['port'])
offset += 2
x += 1
for elem in ip_table:
print elem
return ret,peers
else:
#an error occured, try and extract the error string
error = struct.unpack_from("!s", buf, 8)
print "Action="+str(action)
raise RuntimeError("Error while annoucing: %s" % error)
def udp_create_connection_request():
connection_id = 0x41727101980 #default connection id
action = 0x0 #action (0 = give me a new connection id)
transaction_id = udp_get_transaction_id()
print "1.Transaction ID :", transaction_id
buf = struct.pack("!q", connection_id) #first 8 bytes is connection id
buf += struct.pack("!i", action) #next 4 bytes is actionudp_create_announce_request
buf += struct.pack("!i", transaction_id) #next 4 bytes is transaction id
return (buf, transaction_id)
def udp_parse_connection_response(buf, sent_transaction_id):
if len(buf) < 16:
raise RuntimeError("Wrong response length getting connection id: %s" % len(buf))
action = struct.unpack_from("!i", buf)[0] #first 4 bytes is action
res_transaction_id = struct.unpack_from("!i", buf, 4)[0] #next 4 bytes is transaction id
if res_transaction_id != sent_transaction_id:
raise RuntimeError("Transaction ID doesnt match in connection response! Expected %s, got %s"
% (sent_transaction_id, res_transaction_id))
if action == 0x0:
connection_id = struct.unpack_from("!q", buf, 8)[0] #unpack 8 bytes from byte 8, should be the connection_id
return connection_id
elif action == 0x3:
error = struct.unpack_from("!s", buf, 8)
raise RuntimeError("Error while trying to get a connection response: %s" % error)
pass
def udp_get_transaction_id():
return int(random.randrange(0, 255))