Avoid spurious re-launch of first pending requested descriptor
[tor.git] / contrib / ExerciseServer.py
bloba4c1046a1152b8c7064918604c97e9d8f173793e
1 #!/usr/bin/python
3 import TorControl
4 import threading
5 import socket
6 import struct
7 import random
9 SOCKS_PORT=9050
10 CONTROL_PORT=9051
12 def runSocks4A(nonce, targetHost, targetPort, targetURL):
13 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
14 s.connect(("127.0.0.1", SOCKS_PORT))
15 socksheader = struct.pack("!BBHL", 4, 0x01, targetPort, 1)
16 username = ""
17 socksheader = "%s%s\x00%s\x00" %(socksheader, username, nonce)
18 s.send(socksheader)
19 response = s.recv(8)
20 version,status,port=struct.unpack("!BBH",response[:4])
21 if status != 90:
22 print "Error: non-successful SOCKS status"
23 s.close()
24 return 0
26 s.send("GET %s HTTP/1.0\r\nHost: %s\r\n\r\n"%(targetURL,targetHost))
27 while 1:
28 r = s.recv(1024)
29 if not r:
30 print "WOOT! Got a web page."
31 s.close()
32 return 1
34 HOSTS_TO_TEST = [ "serifos", "chaoscomputerclub", "NetWorkXXIII", "caethaver2",
35 "theoryorg", "samaire", "alrua", "ihopethisisunique",
36 "xolotl", "cacophony", "ghettocluster", "torserverzillion",
37 "ned", "richhomednsorg", "subzeronet"]
38 EXITS_TO_TEST = [ "pvt", ]
40 HOSTS_THAT_WORK = [ "serifos", "rodos", "moria2", "chaoscomputerclub"]
41 EXITS_THAT_WORK = [ "serifos", "rodos"]
43 TARGETS = [ ("belegost.mit.edu", "/"),
44 ("seul.org", "/")]
46 N_CIRCS_TO_TRY = 5*len(HOSTS_TO_TEST)
47 CIRCS_AT_A_TIME = 3
48 CIRC_LEN = 3
50 HOST_STATUS = {}
51 N_CIRCS_DONE = 0
52 def launchCirc(s):
53 htw = HOSTS_THAT_WORK[:]
54 random.shuffle(htw)
55 path = htw[:CIRC_LEN-2] + \
56 [random.choice(HOSTS_TO_TEST)] + \
57 [random.choice(EXITS_THAT_WORK)]
58 circid = TorControl.extend_circuit(s, 0, path)
60 for name in path:
61 lst = HOST_STATUS.setdefault(name,[0,0])
62 lst[0] += 1
63 return circid, path
65 def runControl(s):
66 circs = {}
67 s1,s2 = {},{}
68 _h = lambda body,circs=circs,s1=s1,s2=s2,s=s:handleEvent(s,body,
69 circs,s1,s2)
70 TorControl._event_handler = _h
71 TorControl.set_events(s,
72 [TorControl.EVENT_TYPE.CIRCSTATUS,
73 TorControl.EVENT_TYPE.STREAMSTATUS])
74 TorControl.set_option(s,"__LeaveStreamsUnattached 1")
75 global N_CIRCS_DONE
76 while N_CIRCS_DONE < N_CIRCS_TO_TRY:
77 while len(circs) < CIRCS_AT_A_TIME:
78 c,p = launchCirc(s)
79 print "launching circuit %s to %s"%(c,p)
80 circs[c]=p
81 _, tp, body = TorControl.receive_message(s)
82 if tp == TorControl.MSG_TYPE.EVENT:
83 handleEvent(s, body, circs, s1,s2)
84 i = HOST_STATUS.items()
85 i.sort()
86 for n,(all,good) in i:
87 print "%s in %s circuits; %s/%s ok"%(n,all,good,all)
89 def handleEvent(s, body, circs, streamsByNonce, streamsByIdent):
90 global N_CIRCS_DONE
91 event, args = TorControl.unpack_event(body)
92 if event == TorControl.EVENT_TYPE.STREAMSTATUS:
93 status, ident, target = args
94 print "Got stream event:",TorControl.STREAM_STATUS.nameOf[status],\
95 ident,target
96 if status in (TorControl.STREAM_STATUS.NEW_CONNECT,
97 TorControl.STREAM_STATUS.NEW_RESOLVE,
98 TorControl.STREAM_STATUS.DETACHED):
99 target,port=target.split(":")
100 if not target.endswith(".exnonce"):
101 TorControl.attach_stream(s, ident, 0)
102 else:
103 circid, (host,url) = streamsByNonce[target]
104 streamsByIdent[ident] = circid,(host,url)
105 print "Redirecting circuit",circid,"to",host
106 TorControl.redirect_stream(s, ident, host)
107 TorControl.attach_stream(s, ident, circid)
108 elif status in (TorControl.STREAM_STATUS.CLOSED,
109 TorControl.STREAM_STATUS.FAILED):
110 circid, (host,url) = streamsByIdent[ident]
111 if circs.has_key(circid):
112 for name in circs[circid]:
113 HOST_STATUS[name][1] += 1
114 del circs[circid]
115 N_CIRCS_DONE += 1
116 print N_CIRCS_DONE, "circuit attempts done"
117 del streamsByIdent[ident]
118 elif event == TorControl.EVENT_TYPE.CIRCSTATUS:
119 status, ident, path = args
120 print "Got circuit event",TorControl.CIRC_STATUS.nameOf[status],\
121 ident,path
122 if status in (TorControl.CIRC_STATUS.CLOSED,
123 TorControl.CIRC_STATUS.FAILED):
124 if circs.has_key(ident):
125 print "Circuit failed."
126 del circs[ident]
127 N_CIRCS_DONE += 1
128 print N_CIRCS_DONE, "circuit attempts done"
129 elif status == TorControl.CIRC_STATUS.BUILT:
130 nonce = random.randint(1,100000000)
131 nonce = "%s.exnonce" % nonce
132 host,url = random.choice(TARGETS)
133 streamsByNonce[nonce] = ident, (host,url)
134 print "Launching socks4a connection"
135 t = threading.Thread(target=runSocks4A, args=(nonce, host, 80, url))
136 t.setDaemon(1)
137 t.start()
140 def run():
141 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
142 s.connect(("127.0.0.1", CONTROL_PORT))
143 TorControl.authenticate(s)
144 runControl(s)
146 if __name__ == '__main__':
147 run()