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 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)