authority_nodes = Node.create(3, { "tag": "a", "authority": 1, "relay": 1, "torrc": "authority.tmpl" }) # hidden service (hs) nodes hs_nodes = [] hs_servers = [] port = 8081 from twisted.web import server, resource from twisted.internet import reactor # Use twisted to create web servers in this script class Site(resource.Resource): isLeaf = True numberRequests = 0 def __init__(self, siteNum): self.siteNum = siteNum def render_GET(self, request): self.numberRequests += 1 request.setHeader("content-type", "text/plain") return str(self.siteNum) base_port = 9080 for i in range(2): port = base_port + i node = Node( tag="h", hiddenservice=1, torrc="hidden-service.tmpl", hiddenservicetarget="127.0.0.1:%i" % port ) hs_nodes.append(node) site = server.Site(Site(i)) s = reactor.listenTCP(port, site) hs_servers.append(s) port += 1 client_nodes = Node.create(6, { "tag": "c", "torrc": "client.tmpl" }) relay_nodes = Node.create(10, { "tag": "r", "relay": 1, "torrc": "intro.tmpl" }) thread.start_new_thread(reactor.run, (), {"installSignalHandlers": 0}) initial_nodes = authority_nodes + relay_nodes + client_nodes + hs_nodes[:1] def start(): if not all([ n.getController().start() for n in initial_nodes ]): return False logging.info("All initial nodes running") for n in authority_nodes + relay_nodes: fingerprint = n.getStemController().get_info("fingerprint") nodes_by_fingerprint[fingerprint] = n track_introduction_points(hs_nodes[0]) def hs_node_0_listener(logevent): if "Successfully uploaded v2 rend descriptors" in logevent.message: hs_nodes[0].getStemController().remove_event_listener(hs_node_0_listener) hs_nodes[1].getController().start() track_introduction_points(hs_nodes[1]) def hs_node_1_listener(logevent): if "Successfully uploaded v2 rend descriptors" in logevent.message: hs_nodes[1].getStemController().remove_event_listener(hs_node_1_listener) thread.start_new_thread(test_intro_failure, ()) logging.info("out of node 1 listener") hs_nodes[1].getStemController().add_event_listener(hs_node_1_listener, EventType.INFO) hs_nodes[0].getStemController().add_event_listener(hs_node_0_listener, EventType.INFO) def test_intro_failure(): connection_test() time.sleep(5) # Select a random node that is being used as an introduction point nodenum = random.choice(node_intro_circuits.keys()) fingerprint = random.choice(node_intro_circuits[nodenum].values()) node = nodes_by_fingerprint[fingerprint] logging.info("stopping " + node._env["nick"] + " (" + fingerprint + ")") node.getController().stop() logging.info("begining to watch for the establishment of new introduction points") changed = [False for n in hs_nodes] intro_points_before = [set(node_intro_circuits[n._env["nodenum"]].values()) for n in hs_nodes] time.sleep(90) intro_points_after = [set(node_intro_circuits[n._env["nodenum"]].values()) for n in hs_nodes] for i, node in enumerate(hs_nodes): before = intro_points_before[i] after = intro_points_after[i] if before != after: changed[i] = True if all(changed): logging.info("All changed") else: logging.info("All did not change") check_same_intro_points() connection_test() for server in hs_servers: server.stopListening() reactor.stop() logging.info("stopped the reactor") stop() def connection_test(): logging.info("connecting to clients") responses = {"0": 0, "1": 0} for c in client_nodes: result = c.query("http://2oiifbe3wne4iaqb.onion/"); if result in responses: responses[result] += 1 else: logging.info("Unknown response:") logging.info(str(responses)) ## Utility Code # Introduction Point Tracking node_intro_circuits = {} node_intro_events = {} # node_events introduction_point_circuits = {} nodes_by_fingerprint = {} #{ nodenum: { circuit: "fingerprint", circuit: "fingerprint" } } def track_introduction_points(node): nodenum = node._env["nodenum"] nodenick = node._env["nick"] node_intro_circuits[nodenum] = {} node_intro_events[nodenum] = Queue.Queue() def listener(logevent): prefix = "rend_service_intro_has_opened(): Established circuit " if logevent.message.startswith(prefix): circuit = logevent.message[len(prefix):].split(" ")[0] fingerprint = logevent.message[len(prefix):].split(" ")[1][1:] node_intro_circuits[nodenum][circuit] = fingerprint added_intro_node = nodes_by_fingerprint[fingerprint] logging.info("%s: added %s (%s)" % (nodenick, added_intro_node._env["nick"], fingerprint)) node_intro_events[nodenum].put(("added", fingerprint)) prefix = "rend_services_introduce(): Giving up on " if logevent.message.startswith(prefix) or "Giving up on" in logevent.message: fingerprint = logevent.message[len(prefix):].split(" ")[0][1:41] for_deletion = [] for circuit, fp in node_intro_circuits[nodenum].iteritems(): #log("circuit " + str(circuit) + " fp " + str(fp)) if fingerprint == fp: for_deletion.append(circuit) if len(for_deletion) == 0: logging.info("got log message " + logevent.message + " but not deleting an introduction point") for circuit in for_deletion: fingerprint = node_intro_circuits[nodenum][circuit] removed_intro_node = nodes_by_fingerprint[fingerprint] logging.info("%s: removed %s (%s)" % (nodenick, removed_intro_node._env["nick"], fingerprint)) node_intro_events[nodenum].put(("removed", fingerprint)) del node_intro_circuits[nodenum][circuit] logging.debug(nodenick + ": " + logevent.message) node.getStemController().add_event_listener(listener, EventType.INFO) logging.info("Tracking introduction points for " + node._env["nick"]) def track_introduction_point(node): nodenum = node._env["nodenum"] nodenick = node._env["nick"] introduction_point_circuits[node] = {} def listener(logevent): prefix = " " if logevent.message.startswith(prefix): circuit = logevent.message[len(prefix):].split(" ")[0] fingerprint = logevent.message[len(prefix):].split(" ")[1][1:] node_intro_circuits[nodenum][circuit] = fingerprint added_intro_node = nodes_by_fingerprint[fingerprint] logging.info("%s: added %s (%s)" % (nodenick, added_intro_node._env["nick"], fingerprint)) node_intro_events[nodenum].put(("added", fingerprint)) prefix = "rend_services_introduce(): Giving up on " if logevent.message.startswith(prefix) or "Giving up on" in logevent.message: logging.info(logevent.message) fingerprint = logevent.message[len(prefix):].split(" ")[0][1:41] for_deletion = [] for circuit, fp in node_intro_circuits[nodenum].iteritems(): #log("circuit " + str(circuit) + " fp " + str(fp)) if fingerprint == fp: for_deletion.append(circuit) if len(for_deletion) == 0: logging.info("got log message " + logevent.message + " but not deleting an introduction point") for circuit in for_deletion: fingerprint = node_intro_circuits[nodenum][circuit] removed_intro_node = nodes_by_fingerprint[fingerprint] logging.info("%s: removed %s (%s)" % (nodenick, removed_intro_node._env["nick"], fingerprint)) node_intro_events[nodenum].put(("removed", fingerprint)) del node_intro_circuits[nodenum][circuit] node.getStemController().add_event_listener(listener, EventType.INFO) logging.info("Tracking introduction points for " + node._env["nick"]) def determine_max_load(service_url, clients): request_queue = Queue.Queue(1000) singlelock = threading.Lock() responses = [] running = True class worker(threading.Thread): def __init__ (self, client): super(worker, self).__init__() self.client = client def run(self): while running: try: request = request_queue.get(True, 1) print("making request") result = self.client.query("http://2oiifbe3wne4iaqb.onion/"); singlelock.acquire() responses.append((result, time.time())) print("result " + str(result)) singlelock.release() # Let the queue know the job is finished. request_queue.task_done() except: pass # Create worker threads for client in clients: worker(client).start() # Add elements to eueue at rate current_load # Check size of queue, if above limit, return current_load while True: # Determine Average Load time_barrier = time.time() - 10.0 last_responses = [] singlelock.acquire() for response, response_time in reversed(responses): if response_time < time_barrier: break last_responses.append(response) singlelock.release() current_average_load = len(last_responses) / 10.0 print("current average load %f" % current_average_load) new_load = int(current_average_load) + 1 time_per_item = 1.0 / new_load for i in range(new_load): print("putting in item") request_queue.put(1) time.sleep(time_per_item) def check_same_intro_points(): intro_sets = [] for introduction_points in node_intro_circuits.values(): intro_sets.append(set(introduction_points.values())) if intro_sets[0].issubset(intro_sets[1]) and intro_sets[1].issubset(intro_sets[0]): logging.info("Same introduction points") for fingerprint in node_intro_circuits.values()[0].values(): node = nodes_by_fingerprint[fingerprint] logging.info(" - " + node._env["nick"] + "(" + fingerprint + ")") return True else: logging.info("Not the same introduction points") for num, circuits in node_intro_circuits.items(): logging.info("node %i" % num) for fingerprint in circuits.values(): node = nodes_by_fingerprint[fingerprint] logging.info(" - " + node._env["nick"] + "(" + fingerprint + ")") return False