class Ability(ns.AbilityBase): _info = ns.AbilityInfo( name='Call another Ability', description='Demonstrate how to call synchronously another ability', ) _option_list = [ ns.ChoiceOpt('option', ['normal', 'bypass_cache'], default='normal', comment='Define if cache must be bypassed when using ' 'generators (except "nb")'), ns.StrOpt('msg', default='I was called by another ability', comment='Message we want to see in our called ability'), ns.NumOpt('nb', default=3, comment='Times to display everything'), ] _dependencies = [('abl_demo_opt', 'base', 'Demo options')] def main(self, **kwargs): # Parameters of the called ability can be set in different way abl = self.get_dependency('abl_demo_opt', nb=self.nb, ip_dst='RandIP6', msg=self.msg) abl.port_dst = 42 abl.option = self.option abl.set_opt("path", "/bin/true") abl.start() self._view.info(abl.result())
class Ability(ns.ThreadedAbilityBase): _info = ns.AbilityInfo( name='Hello from a thread', description='Display an hello message and wait to be stopped to exit', ) _option_list = [ ns.StrOpt('msg', default='Hi there', comment='hello message to display'), ns.NumOpt('sleep_time', default=2, comment='Time to wait before displaying the hello message') ] def main(self): time.sleep(self.sleep_time) self._view.info('{}!'.format(self.msg).capitalize()) self._view.warning('Hit Ctrl+c to stop me') self._wait() self._view.info('Ctrl+c received, exiting…') return 'Done' def howto(self): self._view.delimiter('Hello') self._view.info(""" Display an hello message passed in argument after a defined time. It will then hang until receiving a ctrl+c interrupt. """)
class Ability(ns.ThreadedAbilityBase): _option_list = [ ns.StrOpt( 'cacert_file', '/etc/ssl/certs/ca-certificates.crt', 'Path of a file containing the list of trusted CAs', optional=True ), ns.StrOpt('alpn', None, 'Application-Layer Protocol Negotiation value (as a CSV)', optional=True), ns.StrOpt('cipher_suites', ':'.join([ # List from ANSSI TLS guide v.1.1 p.51 'ECDHE-ECDSA-AES256-GCM-SHA384', 'ECDHE-RSA-AES256-GCM-SHA384', 'ECDHE-ECDSA-AES128-GCM-SHA256', 'ECDHE-RSA-AES128-GCM-SHA256', 'ECDHE-ECDSA-AES256-SHA384', 'ECDHE-RSA-AES256-SHA384', 'ECDHE-ECDSA-AES128-SHA256', 'ECDHE-RSA-AES128-SHA256', 'ECDHE-ECDSA-CAMELLIA256-SHA384', 'ECDHE-RSA-CAMELLIA256-SHA384', 'ECDHE-ECDSA-CAMELLIA128-SHA256', 'ECDHE-RSA-CAMELLIA128-SHA256', 'DHE-RSA-AES256-GCM-SHA384', 'DHE-RSA-AES128-GCM-SHA256', 'DHE-RSA-AES256-SHA256', 'DHE-RSA-AES128-SHA256', 'AES256-GCM-SHA384', 'AES128-GCM-SHA256', 'AES256-SHA256', 'AES128-SHA256', 'CAMELLIA128-SHA256' ]), 'Proposed Ordered Cipher Suite List'), ns.BoolOpt('compress', False, 'Should TLS compression be used?'), ns.ChoiceOpt( 'version', ['SSLv3', 'TLSv1', 'TLSv1.1', 'TLSv1.2'], default='TLSv1.2', comment='SSL/TLS protocol version', ), ns.StrOpt('cert_file', '/etc/ssl/certs/ssl-cert-snakeoil.pem', 'Server Certificate'), ns.StrOpt('key_file', '/etc/ssl/private/ssl-cert-snakeoil.key', 'Server Private Key'), ns.ChoiceOpt('protocol', ['IPv4', 'IPv6'], comment='IPv4 or IPv6'), ns.IpOpt(ns.OptNames.IP_DST, '127.0.0.1', 'Binding IP'), ns.PortOpt(ns.OptNames.PORT_DST, 0, 'Binding Port'), ns.NumOpt('backlog_size', 10, 'Backlog size provided to listen()'), ns.NumOpt('timeout', 30, 'Timeout for sockets'), ns.CallbackOpt(ns.OptNames.CALLBACK, comment='Callback returning a service ability to handle a new connection'), ns.StrOpt('client_info_name', 'client_info', 'Name of the service ability option that will contain the information about the client that is at the other end of the TCP connection' ) ] _info = ns.AbilityInfo( name='TLS Server', description='Binds to a port, accept TLS connections and starts new abilities to handle them', authors=['Florian Maury',], tags=[ns.Tag.TCP_STACK_L4], type=ns.AbilityType.COMPONENT ) def __init__(self, *args, **kwargs): super(Ability, self).__init__(*args, **kwargs) self._stop_evt = threading.Event() def stop(self): super(Ability, self).stop() self._stop_evt.set() def _accept_new_connection(self, s): # accepting the connection clt_sock, clt_info = s.accept() # Getting the service ability new_abl = self.callback() # Giving to the service ability the informations about the client new_abl.set_opt(self.client_info_name, '{}:{}'.format(clt_info[0], clt_info[1])) # Creating the pipes in_pipe_in, in_pipe_out = multiprocessing.Pipe() out_pipe_in, out_pipe_out = multiprocessing.Pipe() new_abl.add_in_pipe(in_pipe_out) new_abl.add_out_pipe(out_pipe_in) # Starting the service ability new_abl.start() return clt_sock, in_pipe_in, out_pipe_out, new_abl def _serve(self, server_sock): to_read = [server_sock] to_write = [] ready_to_read = [] ready_to_write = [] service_abilities = [] while not self._stop_evt.is_set(): # Waiting for sockets to be ready readable, writable, errored = select.select(to_read, to_write, [], 0.1) # Adding the sockets that are ready to the list of the already ready sockets ready_to_write += writable to_write = [x for x in to_write if x not in ready_to_write] ready_to_read += readable to_read = [x for x in to_read if x not in ready_to_read] if len(ready_to_read) > 0: # For each socket that is ready to be read for s in ready_to_read: if s is server_sock: # This socket is the server_sock (the one we can run accept upon) new_sock, new_in_pipe, new_out_pipe, new_abl = self._accept_new_connection(s) to_read.append(new_sock) to_read.append(new_out_pipe) to_read.append(s) to_write.append(new_sock) to_write.append(new_in_pipe) service_abilities.append((new_abl, new_sock, new_in_pipe, new_out_pipe)) ready_to_read.pop(ready_to_read.index(s)) else: # The socket is one of the socket connected to a client # StopIteration should not happen because we know that the element must be present # We also know that there should be only one answer so calling on next is efficient # Finally, we use a generator expression because it is more efficient (only generates up to the # first matching occurrence. A list expression would have iterated over the whole list abl, sock, in_pipe, out_pipe = next( (srv for srv in service_abilities if s is srv[1] or s is srv[3]) ) if s is sock and in_pipe in ready_to_write: try: in_pipe.send(s.recv(65535)) to_read.append(s) to_write.append(in_pipe) except: abl.stop() sock.close() in_pipe.close() out_pipe.close() abl.join() finally: ready_to_write.pop(ready_to_write.index(in_pipe)) ready_to_read.pop(ready_to_read.index(sock)) elif s is out_pipe and sock in ready_to_write: try: sock.send(out_pipe.recv()) to_read.append(out_pipe) to_write.append(sock) except: abl.stop() sock.close() in_pipe.close() out_pipe.close() abl.join() finally: ready_to_write.pop(ready_to_write.index(sock)) ready_to_read.pop(ready_to_read.index(out_pipe)) for abl, sock, in_pipe, out_pipe in service_abilities: abl.stop() sock.close() in_pipe.close() out_pipe.close() abl.join() def main(self): # Check Python version py_ver = sys.version_info if ( py_ver.major < 2 or ( py_ver.major == 2 and ( py_ver.minor < 7 or (py_ver.minor >= 7 and py_ver.micro < 10) ) ) ): raise Exception('Your version of Python and Python-ssl are too old. Please upgrade to more "current" versions') # Set up SSL/TLS context tls_version_table = { 'SSLv3': ssl.PROTOCOL_SSLv23, 'TLSv1': ssl.PROTOCOL_TLSv1, 'TLSv1.1': ssl.PROTOCOL_TLSv1_1, 'TLSv1.2': ssl.PROTOCOL_TLSv1_2, } tls_version = tls_version_table[self.version] ctx = ssl.SSLContext(tls_version) if not isinstance(self.alpn, type(None)): ctx.set_alpn_protocols(','.join(self.alpn)) ctx.set_ciphers(self.cipher_suites) if not isinstance(self.cacert_file, type(None)): ctx.load_verify_locations(cafile=self.cacert_file) ctx.load_cert_chain(self.cert_file, self.key_file) if self.protocol == 'IPv4': server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) else: server_sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) ssl_sock = ctx.wrap_socket(server_sock, server_side=True) ssl_sock.bind(('' if isinstance(self.ip_dst, type(None)) else self.ip_dst, self.port_dst)) ssl_sock.listen(self.backlog_size) ssl_sock.settimeout(self.timeout) self._serve(ssl_sock) try: server_sock = ssl_sock.unwrap() server_sock.shutdown(socket.SHUT_RDWR) except: pass finally: server_sock.close()
class Ability(ns.ThreadedAbilityBase): _option_list = [ ns.StrOpt('cacert_file', '/etc/ssl/certs/ca-certificates.crt', 'Path of a file containing the list of trusted CAs'), ns.StrOpt('alpn', None, 'Application-Layer Protocol Negotiation value (as a CSV)', optional=True), ns.StrOpt( 'cipher_suites', ':'.join([ # List from ANSSI TLS guide v.1.1 p.51 'ECDHE-ECDSA-AES256-GCM-SHA384', 'ECDHE-RSA-AES256-GCM-SHA384', 'ECDHE-ECDSA-AES128-GCM-SHA256', 'ECDHE-RSA-AES128-GCM-SHA256', 'ECDHE-ECDSA-AES256-SHA384', 'ECDHE-RSA-AES256-SHA384', 'ECDHE-ECDSA-AES128-SHA256', 'ECDHE-RSA-AES128-SHA256', 'ECDHE-ECDSA-CAMELLIA256-SHA384', 'ECDHE-RSA-CAMELLIA256-SHA384', 'ECDHE-ECDSA-CAMELLIA128-SHA256', 'ECDHE-RSA-CAMELLIA128-SHA256', 'DHE-RSA-AES256-GCM-SHA384', 'DHE-RSA-AES128-GCM-SHA256', 'DHE-RSA-AES256-SHA256', 'DHE-RSA-AES128-SHA256', 'AES256-GCM-SHA384', 'AES128-GCM-SHA256', 'AES256-SHA256', 'AES128-SHA256', 'CAMELLIA128-SHA256' ]), 'Proposed Ordered Cipher Suite List'), ns.BoolOpt('compress', False, 'Should TLS compression be used?'), ns.ChoiceOpt( 'version', ['SSLv3', 'TLSv1', 'TLSv1.1', 'TLSv1.2'], default='TLSv1.2', comment='SSL/TLS protocol version', ), ns.StrOpt('cert_file', None, 'Client Certificate', optional=True), # To be set only in case of mutual authn ns.StrOpt('key_file', None, 'Client Private Key', optional=True), # To be set only in case of mutual authn ns.ChoiceOpt('protocol', ['IPv4', 'IPv6'], comment='IPv4 or IPv6'), ns.IpOpt(ns.OptNames.IP_SRC, None, 'Local (Source) IP', optional=True), ns.IpOpt(ns.OptNames.IP_DST, '127.0.0.1', 'Remote (Destination) IP'), ns.StrOpt('hostname', None, 'Remote Name (dnsName)', optional=True), ns.PortOpt(ns.OptNames.PORT_SRC, 0, 'Local (Source) Port (0 = Random Port)'), ns.PortOpt(ns.OptNames.PORT_DST, 0, 'Remote (Destination) Port'), ns.OptionTemplateEntry(lambda x: 0 <= x <= 10, ns.NumOpt('timeout', 5, 'Connect Timeout')) ] _info = ns.AbilityInfo( name='TLS Client', description='Connects then sends and receives TLS records', authors=['Florian Maury'], tags=[ns.Tag.TCP_STACK_L4], type=ns.AbilityType.COMPONENT) def __init__(self, *args, **kwargs): super(Ability, self).__init__(*args, **kwargs) self._stop_evt = threading.Event() def stop(self): super(Ability, self).stop() self._stop_evt.set() def _serve(self, ssl_sock): to_read = [ssl_sock] + self._builtin_in_pipes to_write = [ssl_sock] + self._builtin_out_pipes ready_to_read = [] ready_to_write = [] while not self._stop_evt.is_set(): # Waiting for sockets to be ready readable, writable, errored = select.select( to_read, to_write, [], 0.1) # Adding the sockets that are ready to the list of the already ready sockets ready_to_write += writable to_write = [x for x in to_write if x not in ready_to_write] ready_to_read += readable to_read = [x for x in to_read if x not in ready_to_read] if len(ready_to_read) > 0: # For each socket that is ready to be read for s in ready_to_read: if s is ssl_sock and all([ out in ready_to_write for out in self._builtin_out_pipes ]): try: msg = ssl_sock.recv(65535) if len(msg) == 0: raise EOFError self._send(msg) to_read.append(ssl_sock) to_write += self._builtin_out_pipes except: self.stop() finally: ready_to_read.pop(ready_to_read.index(s)) for out in self._builtin_out_pipes: ready_to_write.pop(ready_to_write.index(out)) elif s in self._builtin_in_pipes and ssl_sock in ready_to_write: try: ssl_sock.send(self._recv()) to_read += self._builtin_in_pipes to_write.append(ssl_sock) except: self.stop() finally: for p in self._builtin_in_pipes: ready_to_read.pop(ready_to_read.index(p)) ready_to_write.pop(ready_to_write.index(ssl_sock)) def main(self): # Check Python version py_ver = sys.version_info if (py_ver.major < 2 or (py_ver.major == 2 and (py_ver.minor < 7 or (py_ver.minor >= 7 and py_ver.micro < 10)))): raise Exception( 'Your version of Python and Python-ssl are too old. Please upgrade to more "current" versions' ) if self._is_sink() or self._is_source(): raise Exception( 'This ability must be connected through pipes to other abilities!' ) # Set up SSL/TLS context tls_version_table = { 'SSLv3': ssl.PROTOCOL_SSLv23, 'TLSv1': ssl.PROTOCOL_TLSv1, 'TLSv1.1': ssl.PROTOCOL_TLSv1_1, 'TLSv1.2': ssl.PROTOCOL_TLSv1_2, } tls_version = tls_version_table[self.version] ctx = ssl.SSLContext(tls_version) if not isinstance(self.alpn, type(None)): ctx.set_alpn_protocols(','.join(self.alpn)) ctx.set_ciphers(self.cipher_suites) ctx.load_verify_locations(cafile=self.cacert_file) if isinstance(self.key_file, type(None)) ^ isinstance( self.cert_file, type(None)): raise Exception( 'Both key_file and cert_file must be set or none of them.') if not isinstance(self.key_file, type(None)): ctx.load_cert_chain(self.cert_file, self.key_file) if self.protocol == 'IPv4': s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) else: s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) if isinstance(self.hostname, type(None)): ssl_sock = ctx.wrap_socket(s) else: ssl_sock = ctx.wrap_socket(s, server_hostname=self.hostname) ssl_sock.bind( ('' if isinstance(self.ip_src, type(None)) else self.ip_src, self.port_src)) ssl_sock.connect((self.ip_dst, self.port_dst)) self._serve(ssl_sock) try: s = ssl_sock.unwrap() s.shutdown(socket.SHUT_RDWR) except: pass finally: s.close()
class Ability(ns.ThreadedAbilityBase): _option_list = [ ns.ChoiceOpt('protocol', ['IPv4', 'IPv6'], comment='IPv4 or IPv6'), ns.IpOpt(ns.OptNames.IP_SRC, None, 'Local (Source) IP', optional=True), ns.IpOpt(ns.OptNames.IP_DST, '127.0.0.1', 'Remote (Destination) IP'), ns.PortOpt(ns.OptNames.PORT_SRC, 0, 'Local (Source) Port (0 = Random Port)'), ns.PortOpt(ns.OptNames.PORT_DST, 0, 'Remote (Destination) Port'), ns.OptionTemplateEntry(lambda x: 0 <= x <= 10, ns.NumOpt('timeout', 5, 'Connect Timeout')) ] _info = ns.AbilityInfo(name='TCP Client', description='Sends and receives segments', authors=[ 'Florian Maury', ], tags=[ns.Tag.TCP_STACK_L4], type=ns.AbilityType.COMPONENT) @staticmethod def _forward_outgoing(sock, stop_evt, poller, receiver): while not stop_evt.is_set(): if poller(0.1): try: s = receiver() except EOFError: break sock.send(str(s)) @staticmethod def _forward_incoming(sock, stop_evt, sender, stopper): # Timeout is set back to 0.1 second for polling purposes sock.settimeout(0.1) while not stop_evt.is_set(): try: s = sock.recv(65535) except socket.timeout: continue if len(s) == 0: # Socket is closed! break sender(s) stopper() def main(self): if self._is_sink() or self._is_source(): raise Exception( 'This ability must be connected through pipes to other abilities!' ) if self.protocol == 'IPv4': s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) else: s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) s.bind(('' if isinstance(self.ip_src, type(None)) else self.ip_src, self.port_src)) s.settimeout(self.timeout) s.connect((self.ip_dst, self.port_dst)) stop_evt = threading.Event() out_thr = threading.Thread(target=self._forward_outgoing, args=(s, stop_evt, self._poll, self._recv)) out_thr.start() in_thr = threading.Thread(target=self._forward_incoming, args=(s, stop_evt, self._send, self.stop)) in_thr.start() self._wait() stop_evt.set() out_thr.join() in_thr.join() s.close()
class Ability(ns.ThreadedAbilityBase): _option_list = [ ns.ChoiceOpt('protocol', ['IPv4', 'IPv6'], comment='IPv4 or IPv6'), ns.IpOpt(ns.OptNames.IP_DST, '127.0.0.1', 'Binding IP'), ns.PortOpt(ns.OptNames.PORT_DST, 0, 'Binding Port'), ns.NumOpt('backlog_size', 10, 'Backlog size provided to listen()'), ns.NumOpt('timeout', 30, 'Timeout for sockets'), ns.CallbackOpt( ns.OptNames.CALLBACK, comment='Callback returning an ability to handle a new connection' ), ns.StrOpt( 'client_info_name', None, 'Name of the service ability option that will contain the information about the client that is at the other end of the TCP connection', optional=True) ] _info = ns.AbilityInfo( name='TCP Server', description= 'Binds to a port, accept connections and starts new abilities to handle them', authors=[ 'Florian Maury', ], tags=[ns.Tag.TCP_STACK_L4], type=ns.AbilityType.COMPONENT) def __init__(self, *args, **kwargs): super(Ability, self).__init__(*args, **kwargs) self._stop_evt = threading.Event() def stop(self): super(Ability, self).stop() self._stop_evt.set() def _accept_new_connection(self, s): # accepting the connection clt_sock, clt_info = s.accept() # Getting the service ability new_abl = self.callback() # Giving to the service ability the information about the client if not isinstance(self.client_info_name, type(None)): new_abl.set_opt(self.client_info_name, '{}:{}'.format(clt_info[0], clt_info[1])) # Creating the pipes in_pipe_in, in_pipe_out = multiprocessing.Pipe() out_pipe_in, out_pipe_out = multiprocessing.Pipe() new_abl.add_in_pipe(in_pipe_out) new_abl.add_out_pipe(out_pipe_in) # Starting the service ability new_abl.start() return clt_sock, in_pipe_in, out_pipe_out, new_abl def _serve(self, server_sock): to_read = [server_sock] to_write = [] ready_to_read = [] ready_to_write = [] service_abilities = [] while not self._stop_evt.is_set(): # Waiting for sockets to be ready readable, writable, errored = select.select( to_read, to_write, [], 0.1) # Adding the sockets that are ready to the list of the already ready sockets ready_to_write += writable to_write = [x for x in to_write if x not in ready_to_write] ready_to_read += readable to_read = [x for x in to_read if x not in ready_to_read] if len(ready_to_read) > 0: # For each socket that is ready to be read for s in ready_to_read: if s is server_sock: # This socket is the server_sock (the one we can run accept upon) new_sock, new_in_pipe, new_out_pipe, new_abl = self._accept_new_connection( s) to_read.append(new_sock) to_read.append(new_out_pipe) to_read.append(s) to_write.append(new_sock) to_write.append(new_in_pipe) service_abilities.append( (new_abl, new_sock, new_in_pipe, new_out_pipe)) ready_to_read.pop(ready_to_read.index(s)) else: # The socket is one of the socket connected to a client # StopIteration should not happen because we know that the element must be present # We also know that there should be only one answer so calling on next is efficient # Finally, we use a generator expression because it is more efficient (only generates up to the # first matching occurrence. A list expression would have iterated over the whole list abl, sock, in_pipe, out_pipe = next( (srv for srv in service_abilities if s is srv[1] or s is srv[3])) if s is sock and in_pipe in ready_to_write: try: in_pipe.send(s.recv(65535)) to_read.append(s) to_write.append(in_pipe) except: abl.stop() sock.close() in_pipe.close() out_pipe.close() abl.join() finally: ready_to_write.pop( ready_to_write.index(in_pipe)) ready_to_read.pop(ready_to_read.index(sock)) elif s is out_pipe and sock in ready_to_write: try: sock.send(out_pipe.recv()) to_read.append(out_pipe) to_write.append(sock) except: abl.stop() sock.close() in_pipe.close() out_pipe.close() abl.join() finally: ready_to_write.pop(ready_to_write.index(sock)) ready_to_read.pop( ready_to_read.index(out_pipe)) for abl, sock, in_pipe, out_pipe in service_abilities: abl.stop() sock.close() in_pipe.close() out_pipe.close() abl.join() def main(self): if self.protocol == 'IPv4': server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) else: server_sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) server_sock.bind( ('' if isinstance(self.ip_dst, type(None)) else self.ip_dst, self.port_dst)) server_sock.listen(self.backlog_size) server_sock.settimeout(self.timeout) self._serve(server_sock) server_sock.close()
class Ability(ns.AbilityBase): _info = ns.AbilityInfo( name='Demo options', description='Demonstrate all available options', tags=[ns.Tag.EXAMPLE], ) _option_list = [ ns.ChoiceOpt('option', ['normal', 'bypass_cache'], default='normal', comment='Define if cache must be bypassed ' 'when using generators (except "nb")'), ns.NumOpt('nb', default=3, comment='Times to display everything'), ns.IpOpt(ns.OptNames.IP_DST, default='127.0.0.1', comment='use as default the standardized dst_ip option name'), ns.StrOpt('msg', default='my message', comment='A string message'), ns.PortOpt(ns.OptNames.PORT_DST, default=2222, comment='A string message'), ns.MacOpt(ns.OptNames.MAC_SRC, default='Mac00', comment='Source MAC address'), ns.BoolOpt('a_bool', default=True, comment='A True/False value'), ns.PathOpt('path', default='pw.ini', comment='Path to an existing file') # must_exist=True), ] def display(self): for i in range(self.nb): self._view.delimiter('Round {}'.format(i + 1)) self._view.info('[{}] - {} - {}'.format(self.mac_src, self.ip_dst, self.port_dst)) self._view.progress('{}'.format(self.msg)) self._view.debug('{}'.format(self.a_bool)) self._view.warning('{} (abs: {})'.format( self.path, os.path.abspath(self.path))) self._view.delimiter() self._view.info('') def display_bypass_cache(self): for i in range(self.nb): self._view.delimiter('Round {}'.format(i + 1)) self._view.info('[{}] - {} - {}'.format( self.get_opt('mac_src', bypass_cache=True), self.get_opt('ip_dst', bypass_cache=True), self.get_opt('port_dst', bypass_cache=True), )) self._view.progress('{}'.format( self.get_opt('msg', bypass_cache=True))) self._view.debug('{}'.format( self.get_opt('a_bool', bypass_cache=True))) self._view.warning('{} (abs: {})'.format( self.get_opt('path', bypass_cache=True), os.path.abspath(self.get_opt('path', bypass_cache=True)))) self._view.delimiter() self._view.info('') def main(self): if self.nb <= 0: self._view.error( 'The number must be greater than 0 ({} given)'.format(self.nb)) return elif self.nb > 2000: self._view.warning('{} rounds is quite a lot! ' 'Please try with a lower number.'.format( self.nb)) return if self.option == 'normal': self.display() elif self.option == 'bypass_cache': self.display_bypass_cache() self._view.success('Done!') return 'Done' def howto(self): self._view.delimiter('Module option demonstration') self._view.info(""" This ability make use of all the PacketWeaver framework supported options. Their names are either specified using a label, or a predefined value using a OptNames.VAL . The latter solution is preferred as it helps getting a clean input interface across different abilities. You may play with the different options, modifying their value with either: - a fixed value - a fixed value randomly drawn (e.g RandIP4() for the dst_ip) - a random generator (e.g RandIP4) The ability will display their value three times so you can see how they behave. """)