class BeaconServer(Server): def __init__(self, port, task_queue): self._port = port self._serving = False self._serving_greenlet = None self._beacon_server = None self._logger = logging.getLogger(__name__) self._task_queue = task_queue def __serve(self): self._logger.info("[BeaconServer] initialized on port " + str(self._port) + " ...") self._beacon_server = DatagramServer(('', self._port), self.__beacon_receiver) self._beacon_server.serve_forever() def __beacon_receiver(self, msg, address): self._task_queue.put([address, msg]) def start_server(self): if not self._serving: self._serving_greenlet = gevent.spawn(self.__serve) self._serving = True gevent.sleep(0) def stop_server(self): if self._serving: gevent.kill(self._serving_greenlet) self._serving = False self._beacon_server.close() self._logger.info("[BeaconServer] shut down")
def close(self): logger.debug("{:s} close".format(self)) logger.debug("SipCall.close {} Session {}".format(self, self.__session)) global g_call_ids g_call_ids[self._call_id] = None self.__state = SipCall.CLOSED # stop timers for name, timer in self._timers.items(): if not timer: continue logger.debug("SipCall timer {} active {} pending {}".format(timer,timer.active,timer.pending)) #if timer.active == True or timer.pending == True: # logger.warn("SipCall Stopping {}".format(name)) timer.stop() self._timers = {} # close rtpStream for n, v in self._rtp_streams.items(): if v: v.close() self._rtp_streams[n] = None self._rtp_streams = {} # close connection connection.close(self)
def test(self): log = [] def handle(message, address): log.append(message) server.sendto('reply-from-server', address) server = DatagramServer('127.0.0.1:9000', handle) server.start() try: run_script(self.path, 'Test_udp_client') finally: server.close() self.assertEqual(log, ['Test_udp_client'])
def test(self): log = [] def handle(message, address): log.append(message) server.sendto('reply-from-server', address) server = DatagramServer('127.0.0.1:9000', handle) server.start() try: run([sys.executable, '-u', 'udp_client.py', 'Test_udp_client'], timeout=10, cwd='../examples/') finally: server.close() self.assertEqual(log, ['Test_udp_client'])
def test(self): log = [] def handle(message, address): log.append(message) server.sendto(b'reply-from-server', address) server = DatagramServer('127.0.0.1:9001', handle) server.start() try: self.run_example() finally: server.close() self.assertEqual(log, [b'Test_udp_client'])
def close(self): logger.debug("{:s} close".format(self)) logger.debug("Closing stream dump (in)") connection.close(self) if len(self._bistream) == 0: return now = datetime.datetime.now() dirname = "%04i-%02i-%02i" % (now.year, now.month, now.day) bistream_path = os.path.join('bistreams', dirname) if not os.path.exists(bistream_path): os.makedirs(bistream_path) fp = tempfile.NamedTemporaryFile( delete=False, prefix="SipCall-{local_port}-{remote_host}:{remote_port}-".format(local_port=self.local.port, remote_host=self.remote.host, remote_port=self.remote.port), dir=bistream_path ) fp.write(b"stream = ") fp.write(str(self._bistream).encode()) fp.close()
class TftpServer(object): """TFTP Server""" TIMEOUT_RETRIES = 5 def __init__(self, template, template_directory, args, timeout=5): self.timeout = float(timeout) self.server = None # server attr - Initialize in start self.root = None self.listener = None # listener socket # A dict of sessions, where each session is keyed by a string like # ip:tid for the remote end. self.sessions = {} # A threading event to help threads synchronize with the server is_running state. self.is_running = gevent.event.Event() self.shutdown = False self._init_vfs(template) logger.debug("TFTP server initialized.") def _init_vfs(self, template): dom = etree.parse(template) self.root_path = dom.xpath("//tftp/tftp_root_path/text()")[0].lower() if len(dom.xpath("//tftp/add_src/text()")) == 0: self.add_src = None else: self.add_src = dom.xpath("//tftp/add_src/text()")[0].lower() self.data_fs_subdir = dom.xpath( "//tftp/data_fs_subdir/text()")[0].lower() # Create a file system. self.vfs, self.data_fs = conpot_core.add_protocol( protocol_name="tftp", data_fs_subdir=self.data_fs_subdir, vfs_dst_path=self.root_path, src_path=self.add_src, ) if self.add_src: logger.info( "TFTP Serving File System from {} at {} in vfs. TFTP data_fs sub directory: {}" .format(self.add_src, self.root_path, self.data_fs._sub_dir)) else: logger.info( "TFTP Serving File System at {} in vfs. TFTP data_fs sub directory: {}" .format(self.root_path, self.data_fs._sub_dir)) logger.debug("TFTP serving list of files : {}".format(", ".join( self.vfs.listdir(".")))) self.root = "/" # Setup root dir. # check for permissions etc. logger.debug("TFTP root {} is a directory".format(self.vfs.getcwd() + self.root)) if self.vfs.access(self.root, 0, os.R_OK): logger.debug("TFTP root {} is readable".format(self.vfs.getcwd() + self.root)) else: raise TftpException("The TFTP root must be readable") if self.vfs.access(self.root, 0, os.W_OK): logger.debug("TFTP root {} is writable".format(self.vfs.getcwd() + self.root)) else: logger.warning( "The TFTP root {} is not writable".format(self.vfs.getcwd() + self.root)) def handle(self, buffer, client_addr): session = conpot_core.get_session( "tftp", client_addr[0], client_addr[1], get_interface_ip(client_addr[0]), self.server._socket.getsockname()[1], ) logger.info( "New TFTP client has connected. Connection from {}:{}. ".format( client_addr[0], client_addr[1])) session.add_event({"type": "NEW_CONNECTION"}) logger.debug("Read %d bytes", len(buffer)) context = tftp_handler.TFTPContextServer(client_addr[0], client_addr[1], self.timeout, self.root, None, None) context.vfs, context.data_fs = self.vfs, self.data_fs if self.shutdown: logger.info( "Shutting down now. Disconnecting {}".format(client_addr)) session.add_event({"type": "CONNECTION_TERMINATED"}) try: context.start(buffer) context.cycle() except TftpTimeout as err: logger.info("Timeout occurred %s: %s" % (context, str(err))) session.add_event({"type": "CONNECTION_TIMEOUT"}) context.retry_count += 1 # TODO: We should accept retries from the user. if context.retry_count >= self.TIMEOUT_RETRIES: logger.info("TFTP: Hit max {} retries on {}, giving up".format( self.TIMEOUT_RETRIES, context)) else: logger.info("TFTP: resending on session %s" % context) context.state.resendLast() except TftpException as err: logger.info( "TFTP: Fatal exception thrown from session {}: {}".format( context, str(err))) session.add_event({"type": "CONNECTION_LOST"}) logger.info("TFTP: terminating connection: {}".format(context)) session.set_ended() context.end() # Gathering up metrics before terminating the connection. metrics = context.metrics if metrics.duration == 0: logger.info("Duration too short, rate undetermined") else: logger.info("Transferred %d bytes in %.2f seconds" % (metrics.bytes, metrics.duration)) logger.info("Average rate: %.2f kbps" % metrics.kbps) logger.info("%.2f bytes in resent data" % metrics.resent_bytes) logger.info("%d duplicate packets" % metrics.dupcount) del context def start(self, host, port): conn = (host, port) # FIXME - sockets should be non-blocking self.listener = gevent.socket.socket(gevent.socket.AF_INET, gevent.socket.SOCK_DGRAM) self.listener.bind(conn) self.listener.settimeout(self.timeout) self.server = DatagramServer(self.listener, self.handle) logger.info("Starting TFTP server at {}".format(conn)) self.server.serve_forever() def stop(self): self.server.close()
class Receiver(object): """ - Start the UDP server on a host and port. Check for permissions to write on the CWD - Accept an incoming connection. Check if the packet is INITRQ type else discard the packet. - Send the ACK with block_no 0. Wait to receive DATA packet - Verify DATA has block_no == ACK block_no + 1 - If yes, write to file. Else discard packet with appropriate error code <No error codes at the moment> - Send ACK with block_no += 1 - repeat till transfer_complete. size(DATA) < or != blk_size. Close File pointers """ def __init__(self, timeout=None): self.client_state = {} # a data structure to store block_number etc per respective socket. # TODO: check whether appending/insertion to a dictionary would be more efficient for any other DS? self.packet_factory = PacketFactory self.listener = None self.timeout = timeout def handle(self, data, address): self._clean_up() # clean-up if address not in self.client_state.keys(): logger.info('New client has connected. Connection from {}:{}'.format(address[0], address[1])) # check data is valid INITRQ. If not, no point in continuing! if self.packet_factory.check_type('initrq', data) and self.packet_factory.is_valid('initrq', data): self.client_state[address] = { 'transfer_complete': False, 'block_number': 0, 'file_obj': None, 'file_name': None, 'last_active': None, 'inactive': (lambda: int(time.time() - self.client_state[address]['last_active'])) } # build_up context - update the last_activity period self.client_state[address]['last_active'] = time.time() # parse the initrq packet # get the filename of the file - store it! self.client_state[address]['file_name'] = self.packet_factory.from_bytes(data) logger.info('Creating new file with name: {} for client {}'.format( self.client_state[address]['file_name'], address )) # next create a file_obj to that file. self.client_state[address]['file_obj'] = FileWriter( self.client_state[address]['file_name'], DATA_SIZE ) # send ack_packet self.send_ack(address) else: logger.warning('Invalid/Malformed INITRQ packet received from client {}'.format(address)) else: # we have already received some data from this client before! # determine type of packet if self.packet_factory.check_type('initrq', data): # May be client hasn't received an ACK. # send the ack again self.send_ack(address) elif self.packet_factory.check_type('data', data): # The packet is DATAPacket. Nice! Parse the contents of the packet block_no, content = self.packet_factory.from_bytes(data) block_no = int(block_no) # covert block no to int if it is a str # check the block_no on the file. Only write when the block_no on the packet +1 than block_number in # client's state if self.client_state[address]['block_number'] == (block_no - 1): # Write to file self.client_state[address]['file_obj'].write_chunk(content) # increment block_no self.client_state[address]['block_number'] += 1 # client is active self.client_state[address]['last_active'] = time.time () elif self.client_state[address]['block_number'] == block_no: # client must have sent the duplicate DATA packet because it received no ack self.send_ack(address) # Ignore all other cases! -- # FIXME: see if there are corner cases remaining # check to see if the size of packet is < MAX_SIZE # If it is, gracefully disconnect the client. Close the file etc. if len(data) < MAX_PACKET_SIZE: logger.info('File Transfer Complete! Wrote {} to disk'.format( self.client_state[address]['file_obj'].name )) self.disconnect_client(address) else: logger.info('Received data from client. But Not of a valid packet type') def send_ack(self, address): # client is active self.client_state[address]['last_active'] = time.time() temp_block_no = self.client_state[address]['block_number'] # create a awk packet. send that packet temp_packet = self.packet_factory.to_bytes(type='ack', block_no=temp_block_no) self.listener.socket.sendto(temp_packet, address) def disconnect_client(self, address): """ Strictly speaking there is no defined way of gracefully closing a UDP connection. We just set the transfer_complete so that buffer is removed by clean_up function :return: """ self.client_state[address]['transfer_complete'] = True def _clean_up(self, purge=False): """ Cleanup our buffer --> client_state. Remove the entries if the client is not longer active """ for client in list(self.client_state): if purge is False: if self.client_state[client]['inactive']() > CONN_TIMEOUT \ or self.client_state[client]['transfer_complete']: _ = self.client_state.pop(client, None) logger.info('Removing client {} context. Either transfer has completed or client has been inactive ' 'for over {} seconds'.format(client, CONN_TIMEOUT)) else: _ = self.client_state.pop(client, None) logger.info('Forcefully purging client {}'.format(client)) def start(self, host, port): conn = (host, port) sock = gevent.socket.socket(gevent.socket.AF_INET, gevent.socket.SOCK_DGRAM) sock.settimeout(self.timeout) sock.bind(conn) self.listener = DatagramServer(sock, self.handle) try: self.listener.serve_forever() except PYGFTError: # FIXME: proper exception handling logger.exception('Unable to parse contents, create file for INITRQ') except socket.timeout: pass except socket.error: pass except KeyboardInterrupt: logger.exception('Received Keyboard Interrupt. Server would gracefully shutdown') self.stop() def stop(self): """Clean up.""" # Delete files if transfer not complete? # Do anything else? self._clean_up(purge=True) self.listener.close()
class TftpServer(object): """TFTP Server""" TIMEOUT_RETRIES = 5 def __init__(self, template, template_directory, args, timeout=5): self.timeout = float(timeout) self.server = None # server attr - Initialize in start self.root = None self.listener = None # listener socket # A dict of sessions, where each session is keyed by a string like # ip:tid for the remote end. self.sessions = {} # A threading event to help threads synchronize with the server is_running state. self.is_running = gevent.event.Event() self.shutdown = False self._init_vfs(template) logger.debug('TFTP server initialized.') def _init_vfs(self, template): dom = etree.parse(template) self.root_path = dom.xpath('//tftp/tftp_root_path/text()')[0].lower() if len(dom.xpath('//tftp/add_src/text()')) == 0: self.add_src = None else: self.add_src = dom.xpath('//tftp/add_src/text()')[0].lower() self.data_fs_subdir = dom.xpath('//tftp/data_fs_subdir/text()')[0].lower() # Create a file system. self.vfs, self.data_fs = conpot_core.add_protocol(protocol_name='tftp', data_fs_subdir=self.data_fs_subdir, vfs_dst_path=self.root_path, src_path=self.add_src) if self.add_src: logger.info('TFTP Serving File System from {} at {} in vfs. TFTP data_fs sub directory: {}'.format( self.add_src, self.root_path, self.data_fs._sub_dir )) else: logger.info('TFTP Serving File System at {} in vfs. TFTP data_fs sub directory: {}'.format( self.root_path, self.data_fs._sub_dir )) logger.debug('TFTP serving list of files : {}'.format(', '.join(self.vfs.listdir('.')))) self.root = '/' # Setup root dir. # check for permissions etc. logger.debug("TFTP root {} is a directory".format(self.vfs.getcwd() + self.root)) if self.vfs.access(self.root, 0, os.R_OK): logger.debug("TFTP root {} is readable".format(self.vfs.getcwd() + self.root)) else: raise TftpException("The TFTP root must be readable") if self.vfs.access(self.root, 0, os.W_OK): logger.debug("TFTP root {} is writable".format(self.vfs.getcwd() + self.root)) else: logger.warning("The TFTP root {} is not writable".format(self.vfs.getcwd() + self.root)) def handle(self, buffer, client_addr): session = conpot_core.get_session('tftp', client_addr[0], client_addr[1], get_interface_ip(client_addr[0]), self.server._socket.getsockname()[1]) logger.info('New TFTP client has connected. Connection from {}:{}. '.format(client_addr[0], client_addr[1])) session.add_event({'type': 'NEW_CONNECTION'}) logger.debug("Read %d bytes", len(buffer)) context = tftp_handler.TFTPContextServer(client_addr[0], client_addr[1], self.timeout, self.root, None, None) context.vfs, context.data_fs = self.vfs, self.data_fs if self.shutdown: logger.info("Shutting down now. Disconnecting {}".format(client_addr)) session.add_event({'type': 'CONNECTION_TERMINATED'}) try: context.start(buffer) context.cycle() except TftpTimeout as err: logger.info("Timeout occurred %s: %s" % (context, str(err))) session.add_event({'type': 'CONNECTION_TIMEOUT'}) context.retry_count += 1 # TODO: We should accept retries from the user. if context.retry_count >= self.TIMEOUT_RETRIES: logger.info("TFTP: Hit max {} retries on {}, giving up".format(self.TIMEOUT_RETRIES, context)) else: logger.info("TFTP: resending on session %s" % context) context.state.resendLast() except TftpException as err: logger.info("TFTP: Fatal exception thrown from session {}: {}".format(context, str(err))) session.add_event({'type': 'CONNECTION_LOST'}) logger.info('TFTP: terminating connection: {}'.format(context)) session.set_ended() context.end() # Gathering up metrics before terminating the connection. metrics = context.metrics if metrics.duration == 0: logger.info("Duration too short, rate undetermined") else: logger.info("Transferred %d bytes in %.2f seconds" % (metrics.bytes, metrics.duration)) logger.info("Average rate: %.2f kbps" % metrics.kbps) logger.info("%.2f bytes in resent data" % metrics.resent_bytes) logger.info("%d duplicate packets" % metrics.dupcount) del context def start(self, host, port): conn = (host, port) # FIXME - sockets should be non-blocking self.listener = gevent.socket.socket(gevent.socket.AF_INET, gevent.socket.SOCK_DGRAM) self.listener.bind(conn) self.listener.settimeout(self.timeout) self.server = DatagramServer(self.listener, self.handle) logger.info('Starting TFTP server at {}'.format(conn)) self.server.serve_forever() def stop(self): self.server.close()
def close(self): logger.debug("{:s} close".format(self)) self._state = SipSession.CLOSED connection.close(self)