def _load_private_key(self): """Load (and generate if necessary) the Tor public and private keys""" log_msg("Loading private key...", 3) try: torKey = os.path.join(Globals.USER_DATA_DIR, "tor_data", "keys", "secret_id_key") if not Files.file_exists(torKey): #have to create it ourselves. First make the folders if necessary: keyFolder = os.path.join(Globals.USER_DATA_DIR, "tor_data", "keys") if not Files.file_exists(keyFolder): os.makedirs(keyFolder) #then generate the key Globals.PRIVATE_KEY = PrivateKey.PrivateKey(1024) #and save it in the appropriate format if not Globals.PRIVATE_KEY.key.save_key(torKey, cipher=None): raise Exception("Failed to save key as PEM!") else: Globals.PRIVATE_KEY = PrivateKey.PrivateKey(torKey) Globals.PUBLIC_KEY = Globals.PRIVATE_KEY.publickey() Globals.FINGERPRINT = TorUtils.fingerprint(Globals.PRIVATE_KEY.n, Globals.PRIVATE_KEY.e) log_msg("Globals.FINGERPRINT = %s" % (Globals.FINGERPRINT), 3) except Exception, error: log_ex(error, "Failed while loading private key data")
def new_desc_event(self, event): """Called when Tor learns a new server descriptor if listenting to NEWDESC events. @param event: the event structure from the Tor controller @type event: NewDescEvent """ self.log_event(event, "NEW_DESC") for fullName in event.idlist: hexId = TorUtils.get_hex_id(fullName) self.torApp.load_relay(hexId)
def does_relay_belong_to_account(self): """can we verify the signature on the hexid? basically, can we prove that the relay and no one else owns that hexid a hexid is derived from the relays public key, so they should be able to sign their id proving ownership sets: self.hexId @return: None""" thumb = TorUtils.fingerprint(self.n) key = PublicKey.PublicKey(self.n, 65537L) if not key.verify(thumb, self.hexIdSig): raise Exception("fingerprint doesn't match") self.hexId = thumb self.update_db()
def or_conn_status_event(self, event): """Called when an OR connection's status changes if listening to ORCONNSTATUS events. @param event: the event structure from the Tor controller @type event: ORConnEvent""" self.log_event(event, "OR_CONN") #is this an IP address or a relay? vals = event.endpoint.split(":") if len(vals) == 2 and isIPAddress(vals[0]): #TODO: handle these events, maybe look up the relay by IP/Port? pass #better be a hexId: else: hexId = TorUtils.get_hex_id(event.endpoint) #do we know about that router? r = self.torApp.get_relay(hexId) if r: r.on_or_event(event)
def __init__(self, event, app, id, finalPath=None): """Create a new Circuit based on an event from the Tor control interface. @param event: The TorCtrl event @param app: The application that this circuit belongs to. @param id: The Circuit id (will be referenced by future TorCtl events) @param finalPath: The sequence of relays that the circuit will go through when finished being built NOTE: internal Circuits might not have been initialized starting from the "LAUNCHED" state because they may have been started before the controller. Thus, no logic about state/status changes should depend on something having happened in response to a previous event, because that event may not have ever happened.""" #call parent constructor: self.__class__.__bases__[0].__init__(self) #: the application that owns this circuit: self.app = app #: a list of all tor circuit status events that happened for this circuit self.events = [] #: this is the current path (routers that have been successfully extended to) self.currentPath = [] #: this is the path that this circuit will hopefully extend to. Not necessarily defined unless isBitBlinderCircuit is True #: (note that this is NOT the routers that have already been extended to) self.finalPath = None #: whether the stream is already FAILED/CLOSED self.done = False #: whether to send payments for this circuit or not: self.sendPayments = True #: the way to pay to for our traffic (sort of weird, this will eventually be part of the circuit itself) self.parClient = None #: whether we're ready for refill_payments calls or not (need to get our global circ id first): self.readyForPayments = False #: how many relay data cells we've payed for: self.payedReadBytes = 0 self.payedWriteBytes = 0 #: how many circuit tokens there were at the last update (used to calculate bandwidth) self.lastPayedReads = 0 self.lastPayedWrites = 0 #: set our id: self.id = id #: whether this circuit successfully made it to BUILT status or not: self.succeeded = None #This indicates that the Circuit was not created by us: if event: #the circuit event handler will not be called for this first event, so #do everything here in the constructor: self.events.append(event) #indicates that this was NOT created by us: self.isBitBlinderCircuit = False #: current status of the circuit self.status = event.status self.reason = event.reason self.remoteReason = event.remote_reason #set the current path, the representation of the currently EXTENDED path #right now: for fullRouterName in event.path: hexId = TorUtils.get_hex_id(fullRouterName) r = self.app.torApp.get_relay(hexId) if r: self.currentPath.append(r) else: log_msg("circ init event has bad router name: %s"%(hexId), 0) #set the final path, the path that attached streams would (have) use(d): if self.status in ("CLOSED", "FAILED", "BUILT"): self.finalPath = [] for fullRouterName in event.path: hexId = TorUtils.get_hex_id(fullRouterName) self.finalPath.append(self.app.torApp.get_relay(hexId)) #also pretend that the stream ended now #NOTE: in this way, endedAt and createdAt might be the same #so be careful not to subtract and divide without checking for zero if self.status in ("CLOSED", "FAILED"): self.endedAt = time.time() self.done = True #in this case, we are the ones who launched the circuit else: if not finalPath: raise Exception("Must provide a path if you dont provide an event!") self.finalPath = copy.copy(finalPath) self.isBitBlinderCircuit = True self.status = "PRELAUNCH" self.reason = None self.remoteReason = None #: any streams waiting for this Circuit to gain a "BUILT" status? self.pendingStreams = set() #: all the streams actually using the Circuit self.streams = set() #: a pointer to the row in the display self.treeRow = None #: when the first stream was attached self.dirtiedAt = None #: inform the app that there has been a new circuit so it can update its list of circuits self.app.on_new_circuit(self) #: when the next payment event is scheduled for self.checkPaymentEvent = None #: whether some Tor control message is in progress that will tell us about the number of payment cells self.paymentCheckInProgress = False #: remote DHT requests that are waiting for the circuit to be built self.queuedDHTRequests = [] #: the RemoteDHTRequest object for getting peers remotely via DHT self.dhtClient = None #: this will be set to True after ADDTOKENS has completed once. Used to prevent premature PAR payments. self.initialTokensAdded = False #: will be triggered when the circuit is ready for streams self.builtDeferred = defer.Deferred()
def circ_status_event(self, event): """Handle circuit_status events. Note that previous events may not have occurred if isBitBlinderCircuit is False NOTE: path and other events referring to routers now use the long names: hex(~|=)name @param event: a circuit status event that just arrived over the Tor control connection @type event: Event""" #update data from event: self.events.append(event) self.status = event.status self.reason = event.reason self.remoteReason = event.remote_reason #this is the current path (routers that have been successfully extended to) self.currentPath = [] for fullRouterName in event.path: hexId = TorUtils.get_hex_id(fullRouterName) r = self.app.torApp.get_relay(hexId) if r: self.currentPath.append(r) else: log_msg("circ status event has bad router name: %s"%(hexId), 0) #circuit has just been created if event.status == "LAUNCHED": return #if circuit just got (effectively) closed (FAILED always goes to CLOSED) if event.status in ("CLOSED", "FAILED"): self.on_done(event.reason, event.remote_reason) #circuit has been close, no streams can be attached if event.status == "CLOSED": return #circuit failed if event.status == "FAILED": if not event.reason: event.reason = "None" if not event.remote_reason: event.remote_reason = "None" log_msg(str(self.id)+" failed: REASON="+event.reason+" REMOTE_REASON="+event.remote_reason, 3, "circuit") return #circuit was successfully extended to the next hop in the path if event.status == "EXTENDED": return #finished a new circuit. now have to do par setup: if event.status == "BUILT": #do we have a final path defined yet? if not self.finalPath: self.finalPath = [] for fullRouterName in event.path: hexId = TorUtils.get_hex_id(fullRouterName) self.finalPath.append(self.app.torApp.get_relay(hexId)) if self.isBitBlinderCircuit and self.sendPayments: #make sure we dont try to attach to a closed circuit if not self.is_ready(): raise Exception("Circuit %d is not ready for message test" % (self.id)) self.status = "PAR_SETUP" #REFACTOR: move all of the parClient stuff into its own separate class def error(failure): if not self.is_done(): if Basic.exception_is_a(failure, [TorCtl.TorCtlClosed, TorCtl.ErrorReply]): log_msg("Failed to create PAR client, closing", 1, "circuit") else: log_ex(failure, "Unexpected failure while starting circuit") self.on_done() def response(result): self.readyForPayments = True self.parClient.send_setup_message() d = self.parClient.start() d.addCallback(response) d.addErrback(error) else: #for Tor and internal circuits that we dont make payments for yet self.on_par_ready() return raise Exception("UNHANDLED CIRCUIT STATUS: " + event.status)
def __init__(self, event, app, id, finalPath=None): """Create a new Circuit based on an event from the Tor control interface. @param event: The TorCtrl event @param app: The application that this circuit belongs to. @param id: The Circuit id (will be referenced by future TorCtl events) @param finalPath: The sequence of relays that the circuit will go through when finished being built NOTE: internal Circuits might not have been initialized starting from the "LAUNCHED" state because they may have been started before the controller. Thus, no logic about state/status changes should depend on something having happened in response to a previous event, because that event may not have ever happened.""" #call parent constructor: self.__class__.__bases__[0].__init__(self) #: the application that owns this circuit: self.app = app #: a list of all tor circuit status events that happened for this circuit self.events = [] #: this is the current path (routers that have been successfully extended to) self.currentPath = [] #: this is the path that this circuit will hopefully extend to. Not necessarily defined unless isBitBlinderCircuit is True #: (note that this is NOT the routers that have already been extended to) self.finalPath = None #: whether the stream is already FAILED/CLOSED self.done = False #: whether to send payments for this circuit or not: self.sendPayments = True #: the way to pay to for our traffic (sort of weird, this will eventually be part of the circuit itself) self.parClient = None #: whether we're ready for refill_payments calls or not (need to get our global circ id first): self.readyForPayments = False #: how many relay data cells we've payed for: self.payedReadBytes = 0 self.payedWriteBytes = 0 #: how many circuit tokens there were at the last update (used to calculate bandwidth) self.lastPayedReads = 0 self.lastPayedWrites = 0 #: set our id: self.id = id #: whether this circuit successfully made it to BUILT status or not: self.succeeded = None #This indicates that the Circuit was not created by us: if event: #the circuit event handler will not be called for this first event, so #do everything here in the constructor: self.events.append(event) #indicates that this was NOT created by us: self.isBitBlinderCircuit = False #: current status of the circuit self.status = event.status self.reason = event.reason self.remoteReason = event.remote_reason #set the current path, the representation of the currently EXTENDED path #right now: for fullRouterName in event.path: hexId = TorUtils.get_hex_id(fullRouterName) r = self.app.torApp.get_relay(hexId) if r: self.currentPath.append(r) else: log_msg( "circ init event has bad router name: %s" % (hexId), 0) #set the final path, the path that attached streams would (have) use(d): if self.status in ("CLOSED", "FAILED", "BUILT"): self.finalPath = [] for fullRouterName in event.path: hexId = TorUtils.get_hex_id(fullRouterName) self.finalPath.append(self.app.torApp.get_relay(hexId)) #also pretend that the stream ended now #NOTE: in this way, endedAt and createdAt might be the same #so be careful not to subtract and divide without checking for zero if self.status in ("CLOSED", "FAILED"): self.endedAt = time.time() self.done = True #in this case, we are the ones who launched the circuit else: if not finalPath: raise Exception( "Must provide a path if you dont provide an event!") self.finalPath = copy.copy(finalPath) self.isBitBlinderCircuit = True self.status = "PRELAUNCH" self.reason = None self.remoteReason = None #: any streams waiting for this Circuit to gain a "BUILT" status? self.pendingStreams = set() #: all the streams actually using the Circuit self.streams = set() #: a pointer to the row in the display self.treeRow = None #: when the first stream was attached self.dirtiedAt = None #: inform the app that there has been a new circuit so it can update its list of circuits self.app.on_new_circuit(self) #: when the next payment event is scheduled for self.checkPaymentEvent = None #: whether some Tor control message is in progress that will tell us about the number of payment cells self.paymentCheckInProgress = False #: remote DHT requests that are waiting for the circuit to be built self.queuedDHTRequests = [] #: the RemoteDHTRequest object for getting peers remotely via DHT self.dhtClient = None #: this will be set to True after ADDTOKENS has completed once. Used to prevent premature PAR payments. self.initialTokensAdded = False #: will be triggered when the circuit is ready for streams self.builtDeferred = defer.Deferred()
def circ_status_event(self, event): """Handle circuit_status events. Note that previous events may not have occurred if isBitBlinderCircuit is False NOTE: path and other events referring to routers now use the long names: hex(~|=)name @param event: a circuit status event that just arrived over the Tor control connection @type event: Event""" #update data from event: self.events.append(event) self.status = event.status self.reason = event.reason self.remoteReason = event.remote_reason #this is the current path (routers that have been successfully extended to) self.currentPath = [] for fullRouterName in event.path: hexId = TorUtils.get_hex_id(fullRouterName) r = self.app.torApp.get_relay(hexId) if r: self.currentPath.append(r) else: log_msg("circ status event has bad router name: %s" % (hexId), 0) #circuit has just been created if event.status == "LAUNCHED": return #if circuit just got (effectively) closed (FAILED always goes to CLOSED) if event.status in ("CLOSED", "FAILED"): self.on_done(event.reason, event.remote_reason) #circuit has been close, no streams can be attached if event.status == "CLOSED": return #circuit failed if event.status == "FAILED": if not event.reason: event.reason = "None" if not event.remote_reason: event.remote_reason = "None" log_msg( str(self.id) + " failed: REASON=" + event.reason + " REMOTE_REASON=" + event.remote_reason, 3, "circuit") return #circuit was successfully extended to the next hop in the path if event.status == "EXTENDED": return #finished a new circuit. now have to do par setup: if event.status == "BUILT": #do we have a final path defined yet? if not self.finalPath: self.finalPath = [] for fullRouterName in event.path: hexId = TorUtils.get_hex_id(fullRouterName) self.finalPath.append(self.app.torApp.get_relay(hexId)) if self.isBitBlinderCircuit and self.sendPayments: #make sure we dont try to attach to a closed circuit if not self.is_ready(): raise Exception( "Circuit %d is not ready for message test" % (self.id)) self.status = "PAR_SETUP" #REFACTOR: move all of the parClient stuff into its own separate class def error(failure): if not self.is_done(): if Basic.exception_is_a( failure, [TorCtl.TorCtlClosed, TorCtl.ErrorReply]): log_msg("Failed to create PAR client, closing", 1, "circuit") else: log_ex( failure, "Unexpected failure while starting circuit") self.on_done() def response(result): self.readyForPayments = True self.parClient.send_setup_message() d = self.parClient.start() d.addCallback(response) d.addErrback(error) else: #for Tor and internal circuits that we dont make payments for yet self.on_par_ready() return raise Exception("UNHANDLED CIRCUIT STATUS: " + event.status)
if __name__ == '__main__': #check if the script is already running: authFileName = "AUTH.PID" processes = [] if os.path.exists(authFileName): pidFile = open(authFileName, "rb") data = pidFile.read() pidFile.close() data = data.split("\n") data.pop() for pid in data: System.kill_process(int(pid)) pidFile = open(authFileName, "wb") #first generate the DirServer entries: dirServers = TorUtils.make_auth_lines(Conf.AUTH_SERVERS) #now make each of the torrc files and delete any leftover data: authConfs = [] for i in range(1, len(Conf.AUTH_SERVERS)+1): data = dirServers + AUTH_TORRC_DATA conf = Conf.AUTH_SERVERS[i-1] found = False for arg in args: if arg == conf["address"]: found = True break if not found: continue dataDir = "tor_data%d" % (i) logFile = "%s/tor%d.out" % (LOG_FOLDER, i) data += "\nDataDirectory %s\n" % (dataDir)