def initialChecks(self, msg, checkerFunc, nextFunc): self._LOGGING_ and self.logger.debug( f"[{self.name}] Header Recv: {msg.printHeader()}") p = self.transformToPacket(msg.content) if p is None: self._LOGGING_ and self.logger.error( f"[ServerWorker {self.id}] cannot convert data to sotp packet, re-sending..." ) return Message("serverworker", self.id, "router", 0, MessageType.STREAM, self.lostPacket().toBytes(), msg.wrapServerQ) if self.checkReinitialization(p): return Message("serverworker", self.id, "router", 0, MessageType.STREAM, self.doReinitialization(p), msg.wrapServerQ) if self.checkTermination(p): self._LOGGING_ and self.logger.info( f"[ServerWorker {self.id}] termination packet detection") return self.doTermination(p, msg.wrapServerQ) if checkerFunc(p) is False: self._LOGGING_ and self.logger.error( f"[ServerWorker {self.id}] {checkerFunc} has failed, re-sending..." ) return Message("serverworker", self.id, "router", 0, MessageType.STREAM, self.lostPacket().toBytes(), msg.wrapServerQ) if self.checkConfirmation(p) is False: self._LOGGING_ and self.logger.error( f"[ServerWorker {self.id}] cannot confirm our last sent packet, re-sending..." ) return Message("serverworker", self.id, "router", 0, MessageType.STREAM, self.lostPacket().toBytes(), msg.wrapServerQ) return nextFunc(p, msg.wrapServerQ)
def signalEntry(self, data): response = [] if data.isTerminateMessage(): self._LOGGING_ and self.logger.debug_all(f"[{self.name}] signalEntry() received a signal terminate") if self.lastPacketRecv and self.sid: termpacket = self.generateTerminatePacket(self.lastPacketRecv) self._LOGGING_ and self.logger.debug_all(f"[{self.name}] signalEntry() coms active, so sending a termination request") not self.comms_broken and response.append(Message("clientworker",0,self.wrappername,0,MessageType.STREAM,termpacket.toBytes())) response.append(Message("clientworker",0,self.wrappername,0,MessageType.SIGNAL,SignalType.TERMINATE)) self.qdata.put(Message("clientworker",0,'datathread',0,MessageType.SIGNAL,SignalType.TERMINATE)) self.exit = True elif self.st == Status.NOT_INITIALIZING and data.isStartMessage(): self._LOGGING_ and self.logger.debug_all(f"[{self.name}] signalEntry() received a signal Start") p = self.generateInitPacket() self.wait_reply = True response.append(Message("clientworker",0,self.wrappername,0,MessageType.STREAM,p.toBytes())) self.lastPacketSent = p self.st = Status.INITIALIZING elif data.isStopMessage(): self._LOGGING_ and self.logger.debug_all(f"[{self.name}] signalEntry() received a signal Stop") self.st = Status.STOPING elif data.isCommunicationBrokenMessage(): self._LOGGING_ and self.logger.debug_all(f"[{self.name}] signalEntry() received a signal CommunicationBrokenMessage") response = self.lookForRetries() elif data.isBufferReady() and self.lastPacketSent is not None: self._LOGGING_ and self.logger.debug_all(f"[{self.name}] signalEntry() received a signal Buffer Ready") if not self.transceiving: self.transceiving = True self._LOGGING_ and self.logger.debug_all(f"[{self.name}] signalEntry() not transceiving so generate a transfer packet") dpacket = self.makeTransferPacket(self.lastPacketRecv) response.append(Message("clientworker",0,self.wrappername,0,MessageType.STREAM,dpacket.toBytes())) else: self._LOGGING_ and self.logger.error(f"[{self.name}] Invalid signal on streamEntry {data}") raise Exception(f"Invalid signal on streamEntry {data}") return response
def captureTcpStream(self): # Create socket and listen while self.conn is None and not self.exit: self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.settimeout(self.timeout) try: self.socket.bind((self.address, self.port)) self.socket.listen(0) self.conn, self.remoteaddr = self.socket.accept() except socket.timeout as te: continue # Allows to check if the application has exited to finish the thread except Exception as e: print(e) self.inbox.put(Message('input', 0, 'overlay', self.id, MessageType.SIGNAL, SignalType.TERMINATE)) return # Empty buffered data, if any while self.buffer and not self.exit: self.conn.send(self.buffer.pop(0)) # socket loop while not self.exit: try: # Block on socket until Timeout result = select.select([self.conn], [], [], self.timeout) if result[0]: rawdata = self.conn.recv(4096) if rawdata and len(rawdata) > 0: self.inbox.put(Message('input', 0, 'overlay', self.id, MessageType.STREAM, rawdata)) elif not self.persist: self._LOGGING_ and self.logger.debug(f"[{self.name}] TCP communication broken. Sending Terminate signal to overlay") self.inbox.put(Message('input', 0, self.name, self.id, MessageType.SIGNAL, SignalType.TERMINATE)) return else: self.conn.close() self.conn = None break except: self.inbox.put(Message('input', 0, self.name, self.id, MessageType.SIGNAL, SignalType.TERMINATE)) return
def captureInput(self, overlay): while True: if overlay.exit: break if system() != 'Windows': polling = poll() try: if system() == 'Windows': # Ugly loop for windows rawdata = stdin.buffer.raw.read(50000) sleep(0.1) else: # Nice loop for unix polling.register(stdin.buffer.raw.fileno(), POLLIN) polling.poll() rawdata = stdin.buffer.raw.read(50000) if rawdata == b'': # assume EOF self._LOGGING_ and self.logger.info( "[MísticaServer] Input is dead") self.Router.join() if rawdata and len(rawdata) > 0 and overlay.hasInput: overlay.inbox.put( Message('input', 0, 'overlay', overlay.id, MessageType.STREAM, rawdata)) except KeyboardInterrupt: self._LOGGING_ and self.logger.info( "[MísticaServer] CTRL+C detected. Passing to overlay") overlay.inbox.put( Message('input', 0, self.Router.overlayModules[0].name, self.Router.overlayModules[0].id, MessageType.SIGNAL, SignalType.TERMINATE)) break return
def doTermination(self,packet): termpacket = self.generateTermResponsePacket(packet) self.st = Status.TERMINATING self.storePackets(packet,termpacket) return [ Message("clientworker",0,self.overlayname,0,MessageType.SIGNAL,SignalType.COMMS_FINISHED), Message("clientworker",0,self.wrappername,0,MessageType.STREAM,termpacket.toBytes()) ]
def lookForRetries(self): if self.checkForRetries(): self._LOGGING_ and self.logger.error(f"[{self.name}] exceeded the maximum number of retries") self.comms_broken = True return [Message("clientworker",0,self.overlayname,0,MessageType.SIGNAL,SignalType.COMMS_BROKEN)] else: packt = self.lostPacket() self.storePackets(packt,packt) return [Message("clientworker",0,self.wrappername,0,MessageType.STREAM,packt.toBytes())]
def doTermination(self, packet, wsrvinbox): self._LOGGING_ and self.logger.debug( f"[ServerWorker {self.id}] initializing Termination process") pollpacket = self.generatePollResponse(packet) self.st = Status.TERMINATING self.storePackets(packet, pollpacket) self.overlay.inbox.put( Message("serverworker", self.id, 'overlay', 0, MessageType.SIGNAL, SignalType.COMMS_FINISHED)) return Message("serverworker", self.id, "router", 0, MessageType.STREAM, pollpacket.toBytes(), wsrvinbox)
def wrapperProcessing(self, data): self._LOGGING_ and self.logger.debug( f"[{self.name}] Processing data from Wrapper. Status: {self.st}") if self.st == Status.INITIALIZING: return self.initialChecks(data, self.checkInitResponse, self.doInitialize) elif self.st == Status.WORKING: return self.initialChecks(data, self.checkWorkResponse, self.doWork) elif self.st == Status.TERMINATING: self.st = Status.NOT_INITIALIZING return [ Message("clientworker", 0, self.overlayname, 0, MessageType.SIGNAL, SignalType.COMMS_FINISHED) ] elif self.st == Status.REINITIALIZING: self._LOGGING_ and self.logger.debug( f"[{self.name}] About to reset session") return self.initialChecks(data, self.checkWorkResponse, self.resetSession) elif self.st == Status.STOPING: return self.initialChecks(data, self.checkForStop, self.initializeStop) else: self._LOGGING_ and self.logger.error( f"[{self.name}] Invalid status on Wrapper Processing: {self.st}" ) raise Exception(f"Invalid status on Wrapper Processing: {self.st}")
def initialChecks(self, data, checkerFunc, nextFunc): try: p = self.transformToPacket(data.content) if self.st != Status.REINITIALIZING and self.checkReinitialization( p): self._LOGGING_ and self.logger.debug( f"[{self.name}] Reinitialization Request Packet detected") return self.doReintialization(p) if self.checkTermination(p): self._LOGGING_ and self.logger.debug( f"[{self.name}] Termination Request Packet detected") return self.doTermination(p) if checkerFunc(p) == False: self._LOGGING_ and self.logger.error( f"[{self.name}] {str(checkerFunc)} has failed, re-sending..." ) return self.lookForRetries() if self.checkConfirmation(p) == False: self._LOGGING_ and self.logger.error( f"[{self.name}] checkConfirmation has failed, lpks: {self.lastPacketSent.seq_number} != ack: {p.ack}" ) return self.lookForRetries() return nextFunc(p) except Exception as e: self._LOGGING_ and self.logger.exception( f"[{self.name}] initialChecks Exception: {e}") return [ Message("clientworker", 0, self.overlayname, 0, MessageType.SIGNAL, SignalType.ERROR) ]
def doReintialization(self,packt): repackt = self.generateReintializationPacket(packt) self.oldst = self.st self.st = Status.REINITIALIZING self.storePackets(packt,repackt) self.seqnumber=0 return [Message("clientworker",0,self.wrappername,0,MessageType.STREAM,repackt.toBytes())]
def getPollRequest(self): if self.lastPacketRecv is None: self._LOGGING_ and self.logger.error(f"[{self.name}] Any previous Packet Received in getPollRequest()") raise Exception("Any previous Packet Received in getPollRequest()") packettosend = self.generatePollPacket(self.lastPacketRecv) self.storePackets(None,packettosend) return [Message("clientworker",0,self.wrappername,0,MessageType.STREAM,packettosend.toBytes())]
def initializeStop(self, packt): stopackt = self.generateTerminatePacket(packt) self.st = Status.TERMINATING self.storePackets(packt, stopackt) return [ Message("clientworker", 0, self.wrappername, 0, MessageType.STREAM, stopackt.toBytes()) ]
def handleInputSignal(self, msg): if msg.isTerminateMessage(): if self.mode == MisticaMode.SINGLE: return Message(self.name, self.id, "router", 0, MessageType.SIGNAL, SignalType.TERMINATE) else: return self.handleInterrupt()
def handleSignal(self, msg): if msg.isTerminateMessage() or msg.isCommunicationEndedMessage( ) or msg.isCommunicationBrokenMessage(): self.exit = True self.qsotp.put( Message(self.name, 0, "clientworker", 0, MessageType.SIGNAL, SignalType.TERMINATE)) pass
def handleStream(self, msg): if self.st == Status.WORKING: self.outbox.put( self.initialChecks(msg, self.checkWorkRequest, self.doWork)) elif self.st == Status.TERMINATING: self.overlay.inbox.put( Message("serverworker", self.id, 'overlay', self.overlay.id, MessageType.SIGNAL, SignalType.COMMS_FINISHED))
def overlayProcessing(self, data): self._LOGGING_ and self.logger.debug( f"[DataThread] {data.sender} sent {len(data.content)} bytes of data, storing..." ) self.storeOverlayContent(data.content) if self.sid and not self.wait_reply and not self.transceiving: return Message("datathread", 0, "clientworker", 0, MessageType.SIGNAL, SignalType.BUFFER_READY) return
def captureInput(self): self.sem.acquire() self._LOGGING_ and self.logger.info(f"[Input] Initializing...") self.sem.release() if system() != 'Windows': polling = poll() while True: if self.overlay.exit: break try: if system() == 'Windows': # Ugly loop for windows rawdata = stdin.buffer.raw.read(300000) sleep(0.1) else: # Nice loop for unix polling.register(stdin.buffer.raw.fileno(), POLLIN) polling.poll() rawdata = stdin.buffer.raw.read(300000) if rawdata == b'': # assume EOF self.sotp_sem.acquire() self._LOGGING_ and self.logger.debug( f"[Input] SOTP initialized, sending terminate because input recv EOF" ) self.overlay.inbox.put( Message("input", 0, self.overlayname, 0, MessageType.SIGNAL, SignalType.TERMINATE)) self.sotp_sem.release() break if rawdata and len(rawdata) > 0 and self.overlay.hasInput: self.overlay.inbox.put( Message("input", 0, self.overlayname, 0, MessageType.STREAM, rawdata)) except KeyboardInterrupt: self._LOGGING_ and self.logger.debug( "[Input] CTRL+C detected. Passing to wrapper") self.overlay.inbox.put( Message("input", 0, self.overlayname, 0, MessageType.SIGNAL, SignalType.TERMINATE)) break self._LOGGING_ and self.logger.info(f"[Input] Terminated") return
def captureTcpStream(self): # Create socket and connect while not self.exit: try: self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.connect((self.address, self.port)) except Exception as e: print(e) self.inbox.put( Message('input', 0, self.name, self.id, MessageType.SIGNAL, SignalType.TERMINATE)) if self.lock.locked(): self.lock.release() return if self.lock.locked(): self.lock.release() while not self.exit: try: # Block on socket result = select.select([self.socket], [], [], self.timeout) if result[0]: rawdata = self.socket.recv(4096) if rawdata and len(rawdata) > 0: self.inbox.put( Message('input', 0, 'overlay', self.id, MessageType.STREAM, rawdata)) elif not self.persist: self._LOGGING_ and self.logger.debug( f"[{self.name}] TCP communication broken. Sending Terminate signal to overlay" ) self.inbox.put( Message('input', 0, self.name, self.id, MessageType.SIGNAL, SignalType.TERMINATE)) return else: self.socket.close() break except Exception as e: self.inbox.put( Message('input', 0, self.name, self.id, MessageType.SIGNAL, SignalType.TERMINATE)) return return
def initializeSOTPSession(self, msg): # Get sender: sender = None for wrapper in self.wrapModules: if wrapper.id == msg.sender_id: sender = wrapper self._LOGGING_ and self.logger.debug( f"[Router] Found {msg.sender} with id {msg.sender_id} in the WrapModule list" ) break else: # not a valid wrapper? self._LOGGING_ and self.logger.error( f"[Router] Error: Wrapper does not exist") return # Check if valid packet try: pkt = Core.transformToPacket(msg.content) except Exception as e: sender.inbox.put(self.errorMessage(sender.name, sender.id)) self._LOGGING_ and self.logger.exception( f"[Router] Exception on transformToPacket() {e}") return # Check if valid overlay tag if not self.validOverlayTag(pkt.content): sender.inbox.put(self.errorMessage(sender.name, sender.id)) self._LOGGING_ and self.logger.error( f"[Router] Error: Not a valid Overlay tag") return # Generate new random ID try: sessionID = self.newSessionID() except Exception as e: self._LOGGING_ and self.logger.exception( f"[Router] Exception on newSessionID() {e}") sender.inbox.put(self.errorMessage(sender.name, sender.id)) return # Add Session ID and overlay tag to pending and send response to wrapper authpkt = self.generateAuthResponsePacket(pkt, sessionID) self.pendingInit.append({ "sessionID": sessionID, "tag": pkt.content, "lastpkt": authpkt }) # Avoid DoS by rejecting old pendings: if len(self.pendingInit) > (Header.SESSION_ID / 2): self.pendingInit.pop(0) self._LOGGING_ and self.logger.debug( f"[Router] Passing Session Response back to {msg.sender}") sender.inbox.put( Message(self.name, self.id, sender.name, sender.id, MessageType.STREAM, authpkt.toBytes(), msg.wrapServerQ))
def handleSOTPSignal(self, msg): answer = None if msg.isTerminateMessage(): self.exit = True elif msg.isCommsFinishedMessage() or msg.isCommsBrokenMessage(): if self.mode == MisticaMode.SINGLE: answer = Message(self.name, self.id, "router", 0, MessageType.SIGNAL, SignalType.TERMINATE) else: self.removeWorker(msg.sender_id) # crashed worker return answer
def sigintDetect(self, signum, frame): self._LOGGING_ and self.logger.info("[Sotp] SIGINT detected") if (self.mode == MisticaMode.SINGLE): targetoverlay = self.Router.overlayModules[0] targetoverlay.inbox.put( Message('input', 0, self.Router.overlayModules[0].name, self.Router.overlayModules[0].id, MessageType.SIGNAL, SignalType.TERMINATE)) else: # TODO: Depends on who's on the foreground pass
def handleStream(self, msg): try: if (msg.sender == self.name): return self.unwrap(msg.content) elif (msg.sender == "clientworker"): self.wrap(msg.content) except Exception as e: m = Message(self.name, 0, "clientworker", 0, MessageType.SIGNAL, SignalType.COMMS_BROKEN) self._LOGGING_ and self.logger.exception( f"[{self.name}] Exception at handleStream: {e}") self.qsotp.put(m)
def doWork(self,packet): response = [] packettosend = None if packet.anyContentAvailable(): self.extractIncomingData(packet) if packet.isFlagActive(Flags.PUSH): data_decrypt = self.decryptWrapperData() response.append(Message("clientworker",0,self.overlayname,0,MessageType.STREAM,data_decrypt)) if self.someOverlayData(): packettosend = self.makeTransferPacket(packet) response.append(Message("clientworker",0,self.wrappername,0,MessageType.STREAM,packettosend.toBytes())) else: packettosend = self.generatePollPacket(packet) response.append(Message("clientworker",0,self.wrappername,0,MessageType.STREAM,packettosend.toBytes())) else: if self.someOverlayData(): packettosend = self.makeTransferPacket(packet) response.append(Message("clientworker",0,self.wrappername,0,MessageType.STREAM,packettosend.toBytes())) else: packettosend = self.generateAckPacket(packet) response.append(Message("clientworker",0,self.wrappername,0,MessageType.STREAM,packettosend.toBytes())) self.wait_reply = True self.transceiving = True else: if self.someOverlayData(): packettosend = self.makeTransferPacket(packet) response.append(Message("clientworker",0,self.wrappername,0,MessageType.STREAM,packettosend.toBytes())) self.wait_reply = True self.transceiving = True else: self.wait_reply = False self.transceiving = False self.storePackets(packet,packettosend) return response
def run(self): # If the mode is single-handler only a wrapper module and overlay module is used if self.mode == MisticaMode.SINGLE: # Launch wrap_module wmitem = self.getModuleInstance(ModuleType.WRAP_MODULE, self.wrappername, self.args["wrapper_args"]) wmitem.start() self.Router.wrapModules.append(wmitem) # Check wrap_server dependency of wrap_module and launch it wsname = self.getDependencyName(self.wrappername) if (not self.dependencyLaunched(self.wrappername)): wsitem = self.getModuleInstance(ModuleType.WRAP_SERVER, wsname, self.args["wrap_server_args"]) wsitem.start() self.Router.wrapServers.append(wsitem) else: for elem in self.Router.wrapServers: if wsname == elem.name: wsitem = elem break # add wrap_module to wrap_server list wsitem.addWrapModule(wmitem) # Launch overlay module omitem = self.getModuleInstance(ModuleType.OVERLAY, self.overlayname, self.args["overlay_args"]) omitem.start() self.Router.overlayModules.append(omitem) targetoverlay = self.Router.overlayModules[0] if targetoverlay.hasInput: self.captureInput(targetoverlay) self.Router.join() self._LOGGING_ and self.logger.debug("[MísticaServer] Terminated") elif self.mode == MisticaMode.MULTI: # Launch prompt etc. # Before registering a wrapper or an overlay, we must make sure that there is no other # module with incompatible parameters (e.g 2 DNS base64-based wrap_modules) self.Router.inbox.put( Message("Mistica", 0, "sotp", 0, MessageType.SIGNAL, SignalType.TERMINATE)) print("Multi-handler mode is not implemented yet! use -h") exit(0)
def resetSession(self,packet): response = [] self.st = self.oldst packettosend = None if self.someOverlayData(): self._LOGGING_ and self.logger.debug(f"[{self.name}] Overlay data detected, making transfer packet...") packettosend = self.makeTransferPacket(packet) response.append(Message("clientworker",0,self.wrappername,0,MessageType.STREAM,packettosend.toBytes())) self.wait_reply = True self.transceiving = True else: self._LOGGING_ and self.logger.debug(f"[{self.name}] No overlay data, waiting...") self.wait_reply = False self.transceiving = False self.storePackets(packet,packettosend) return response
def doInitialize(self,packet): if self.sid is None: self.sid = packet.session_id packettosend = None if self.someOverlayData(): self._LOGGING_ and self.logger.debug(f"[{self.name}] detected Overlay data in doInitialize()") packettosend = self.makeTransferPacket(packet) self.transceiving = True else: self._LOGGING_ and self.logger.debug(f"[{self.name}] generating Polling Request") packettosend = self.generatePollPacket(packet) self.transceiving = False self.wait_reply = True self.storePackets(packet,packettosend) self.st = Status.WORKING return [Message("clientworker",0,self.wrappername,0,MessageType.STREAM,packettosend.toBytes())]
def doWork(self, packet, wsrvinbox): response = None packettosend = None if packet.anyContentAvailable(): self.extractIncomingData(packet) if packet.isFlagActive(Flags.PUSH): data_decrypt = self.decryptWrapperData() self.overlay.inbox.put( Message("serverworker", self.id, 'overlay', 0, MessageType.STREAM, data_decrypt)) if self.someOverlayData(): packettosend = self.makeTransferPacket(packet) response = Message("serverworker", self.id, "router", 0, MessageType.STREAM, packettosend.toBytes(), wsrvinbox) else: packettosend = self.generatePollResponse(packet) response = Message("serverworker", self.id, "router", 0, MessageType.STREAM, packettosend.toBytes(), wsrvinbox) else: if self.someOverlayData(): packettosend = self.makeTransferPacket(packet) response = Message("serverworker", self.id, "router", 0, MessageType.STREAM, packettosend.toBytes(), wsrvinbox) else: packettosend = self.generatePollResponse(packet) response = Message("serverworker", self.id, "router", 0, MessageType.STREAM, packettosend.toBytes(), wsrvinbox) else: if self.someOverlayData(): packettosend = self.makeTransferPacket(packet) response = Message("serverworker", self.id, "router", 0, MessageType.STREAM, packettosend.toBytes(), wsrvinbox) else: packettosend = self.generatePollResponse(packet) response = Message("serverworker", self.id, "router", 0, MessageType.STREAM, packettosend.toBytes(), wsrvinbox) self.storePackets(packet, packettosend) self._LOGGING_ and self.logger.debug( f"[{self.name}] Header Sent: {response.printHeader()}") return response
def craftTerminateMessage(self, receiver, receiver_id): return Message(self.name, self.id, receiver, receiver_id, MessageType.SIGNAL, SignalType.TERMINATE)
def errorMessage(self, destination, destination_id): return Message(self.name, self.id, destination, destination_id, MessageType.SIGNAL, SignalType.ERROR)
def doMulticast(self, q, data): for wrap in self.server.wrappers: msg = Message(self.server.sname, self.server.sid, wrap.name, wrap.id, MessageType.STREAM, data, q) wrap.inbox.put(msg)