def process_inbound_message(self, msg): """ First stage for handling an inbound message: check that it's a known message type, and that the number of arguments is correct; extract sequence numbers, send an ack if its required, if the message is a reply, retrieve any state that was stored when we sent the previous message. Actual functional message handling is organised by .determine_response() """ self.debug_note("Processing inbound %s" % msg, seriousness=-2) # All Switzerland messages should be lists if type(msg) != types.ListType or type(msg[0]) != types.StringType or \ msg[0] not in self.in_messages: self.protocol_error("Invalid message object " + util.screensafe(str)) # Message is a list of: msg_type, [reply_seq_no,] [seq_no,] arguments msg_type = msg[0] m = self.in_messages[msg_type] if len(msg) != m.length: self.protocol_error("Invalid message length %d for %s:\n " % \ (len(msg), util.screensafe(msg))) args = [] offset = 1 seq_no = reply_seq_no = None if m.is_reply: reply_seq_no = int(msg[offset]) offset += 1 # semi-magically arrange for the reply data stored at our end to be passed # to the handler as if it was sent by the other party try: reply_data = self.reply_data_table[reply_seq_no] except: raise del self.reply_data_table[reply_seq_no] args.append(reply_data) if m.expects_ack or m.expects_reply: seq_no = int(msg[offset]) offset += 1 args += msg[offset:] # The rest depends on the specific message if not self.determine_response(msg_type, args, seq_no, reply_seq_no): sys.stderr.write( "Bug in %s.determine_response(), can't handle message %s\n" % ( ` self.__class__ `, ` (msg_type, args, seq_no, reply_seq_no) `)) sys.exit(1) # Ack at the end to ensure it isn't over-confident if m.expects_ack: self.send_message("ack", [seq_no])
def process_inbound_message(self, msg): """ First stage for handling an inbound message: check that it's a known message type, and that the number of arguments is correct; extract sequence numbers, send an ack if its required, if the message is a reply, retrieve any state that was stored when we sent the previous message. Actual functional message handling is organised by .determine_response() """ self.debug_note("Processing inbound %s" % msg, seriousness=-2) # All Switzerland messages should be lists if type(msg) != types.ListType or type(msg[0]) != types.StringType or \ msg[0] not in self.in_messages: self.protocol_error("Invalid message object " + util.screensafe(str)) # Message is a list of: msg_type, [reply_seq_no,] [seq_no,] arguments msg_type = msg[0] m = self.in_messages[msg_type] if len(msg) != m.length: self.protocol_error("Invalid message length %d for %s:\n " % \ (len(msg), util.screensafe(msg))) args = [] offset = 1 seq_no = reply_seq_no = None if m.is_reply: reply_seq_no = int(msg[offset]) offset += 1 # semi-magically arrange for the reply data stored at our end to be passed # to the handler as if it was sent by the other party try: reply_data = self.reply_data_table[reply_seq_no] except: raise del self.reply_data_table[reply_seq_no] args.append(reply_data) if m.expects_ack or m.expects_reply: seq_no = int(msg[offset]) offset += 1 args += msg[offset:] # The rest depends on the specific message if not self.determine_response(msg_type, args, seq_no, reply_seq_no): sys.stderr.write( "Bug in %s.determine_response(), can't handle message %s\n" % (`self.__class__`, `(msg_type, args, seq_no, reply_seq_no)`)) sys.exit(1) # Ack at the end to ensure it isn't over-confident if m.expects_ack: self.send_message("ack", [seq_no])
def handle_myip(self, args, reply_seq_no): "The other side has told us their opinion of their own IP address" peers_public_host, peer_port = self.peer peers_public_host = s.gethostbyname(peers_public_host) ips = args[0] try: self.peers_private_ip = s.gethostbyname(ips[0]) except: self.protocol_error("Invalid peer host:\n %s" % util.screensafe(args[0])) if len(ips) == 2 and self.parent.config.allow_fake_ips: # alice may specify a public ip she wishes to assume peer_host = ips[1] self.parent.faking_ip(self, peer_host) self.fake_ip(peer_host) self.alice_firewalled = ips[0] != ips[1] else: if len(ips) == 2: # Fake IPs are intended for testing. Perhaps in the future we'll # allow them for clients coming in through Tor, but there are security # issues to consider with that log.error("DENYING REQUEST FOR A FAKE IP!") self.send_message("error-cont", ["Denying request for a fake IP"]) # but by default, she'll believe switzerland peer_host = s.gethostbyname(peers_public_host) self.alice_firewalled = peer_host != self.peers_private_ip self.send_message("public-ip", [peer_host], reply_seq_no=reply_seq_no) # XXX the simultaneous use of fake IPs and Alice's filter_packets=True # will break this next message self.send_message("new-members", [self.parent.peers_of(self.peer[0])]) self.parent.joining_circle(self) self.now_ready()
def handle_active_flows(self, link, args): "The active_flows message from Alice updates our state of flows." new_flows, deleted_flows = args # Process deleted flows first, because we might want to delete a flow # and recreate it simultaneously if it has been closed and re-SYNed try: if not self.config.keep_reconciliators: self.debug_note("deleting flows: %s" % deleted_flows) for f_id in deleted_flows: self.mm.delete_flow(link, f_id) except: link.protocol_error("Problem with flow list: %s\n" % util.screensafe(new_flows)) raise # Now the new flows: try: for flow in new_flows: f_id = flow[0] assert len(flow[1]) == Protocol.hash_length, \ "hashlen is not %d in %r" % (Protocol.hash_length, flow) if ipids_in_matchmaker: opening_hash = flow[1] else: opening_hash = flow[1][:-2] f_tuple = flow[2] assert len(f_tuple) == 5 assert type(opening_hash) == str match = self.ponder_flow(link, f_id, f_tuple, opening_hash) if match: self.debug_note("YES", seriousness=-1) self.mm.add_flow(link, f_id, f_tuple, match) else: self.debug_note("NO", seriousness=-1) if not self.config.sloppy: self.debug_note("Mysteriously Irrelevant Flow!!!%s" % `(link.peer[0],print_flow_tuple(f_tuple))`) except: errlog.debug("OH NOES %s", traceback.format_exc()) link.protocol_error("Problem with flow list: %s\n" % util.screensafe(new_flows)) raise