def main(): # For py2exe builds freeze_support() # Handle SIGINT to terminate processes signal.signal(signal.SIGINT, sigint_handler) start_time = time() #--PLUGINS INITIALIZATION-- sslyze_plugins = PluginsFinder() available_plugins = sslyze_plugins.get_plugins() available_commands = sslyze_plugins.get_commands() # Create the command line parser and the list of available options sslyze_parser = CommandLineParser(available_plugins, __version__) online_servers_list = [] invalid_servers_list = [] # Parse the command line try: good_server_list, bad_server_list, args_command_list = sslyze_parser.parse_command_line() invalid_servers_list.extend(bad_server_list) except CommandLineParsingError as e: print e.get_error_msg() return should_print_text_results = not args_command_list.quiet and args_command_list.xml_file != '-' \ and args_command_list.json_file != '-' if should_print_text_results: print '\n\n\n' + _format_title('Available plugins') for plugin in available_plugins: print ' ' + plugin.__name__ print '\n\n' #--PROCESSES INITIALIZATION-- if args_command_list.https_tunnel: # Maximum one process to not kill the proxy plugins_process_pool = PluginsProcessPool(sslyze_plugins, args_command_list.nb_retries, args_command_list.timeout, max_processes_nb=1) else: plugins_process_pool = PluginsProcessPool(sslyze_plugins, args_command_list.nb_retries, args_command_list.timeout) #--TESTING SECTION-- # Figure out which hosts are up and fill the task queue with work to do if should_print_text_results: print _format_title('Checking host(s) availability') connectivity_tester = ServersConnectivityTester(good_server_list) connectivity_tester.start_connectivity_testing() SERVER_OK_FORMAT = ' {host}:{port:<25} => {ip_address} {client_auth_msg}' SERVER_INVALID_FORMAT = ' {server_string:<35} => WARNING: {error_msg}; discarding corresponding tasks.' # Store and print servers we were able to connect to for server_connectivity_info in connectivity_tester.get_reachable_servers(): online_servers_list.append(server_connectivity_info) if should_print_text_results: client_auth_msg = '' client_auth_requirement = server_connectivity_info.client_auth_requirement if client_auth_requirement == ClientAuthenticationServerConfigurationEnum.REQUIRED: client_auth_msg = ' WARNING: Server REQUIRED client authentication, specific plugins will fail.' elif client_auth_requirement == ClientAuthenticationServerConfigurationEnum.OPTIONAL: client_auth_msg = ' WARNING: Server requested optional client authentication' print SERVER_OK_FORMAT.format(host=server_connectivity_info.hostname, port=server_connectivity_info.port, ip_address=server_connectivity_info.ip_address, client_auth_msg=client_auth_msg) # Send tasks to worker processes for plugin_command in available_commands: if getattr(args_command_list, plugin_command): # Get this plugin's options if there's any plugin_options_dict = {} for option in available_commands[plugin_command].get_interface().get_options(): # Was this option set ? if getattr(args_command_list,option.dest): plugin_options_dict[option.dest] = getattr(args_command_list, option.dest) plugins_process_pool.queue_plugin_task(server_connectivity_info, plugin_command, plugin_options_dict) for tentative_server_info, exception in connectivity_tester.get_invalid_servers(): invalid_servers_list.append(('{}:{}'.format(tentative_server_info.hostname, tentative_server_info.port), exception)) # Print servers we were NOT able to connect to if should_print_text_results: for server_string, exception in invalid_servers_list: if isinstance(exception, ServerConnectivityError): print SERVER_INVALID_FORMAT.format(server_string=server_string, error_msg=exception.error_msg) else: # Unexpected bug in SSLyze raise exception print '\n\n' # Keep track of how many tasks have to be performed for each target task_num = 0 for command in available_commands: if getattr(args_command_list, command): task_num += 1 # --REPORTING SECTION-- # XML output xml_output_list = [] # Each host has a list of results result_dict = {} # We cannot use the server_info object directly as its address will change due to multiprocessing RESULT_KEY_FORMAT = '{ip_address}:{port}'.format for server_info in online_servers_list: result_dict[RESULT_KEY_FORMAT(ip_address=server_info.ip_address, port=server_info.port)] = [] # Process the results as they come for plugin_result in plugins_process_pool.get_results(): server_info = plugin_result.server_info result_dict[RESULT_KEY_FORMAT(ip_address=server_info.ip_address, port=server_info.port)].append(plugin_result) result_list = result_dict[RESULT_KEY_FORMAT(ip_address=server_info.ip_address, port=server_info.port)] if len(result_list) == task_num: # Done with this server; print the results and update the xml doc if args_command_list.xml_file: xml_output_list.append(_format_xml_target_result(server_info, result_list)) if should_print_text_results: print _format_txt_target_result(server_info, result_list) # --TERMINATE-- exec_time = time()-start_time # Output JSON to a file if needed if args_command_list.json_file: json_output = {'total_scan_time': str(exec_time), 'network_timeout': str(args_command_list.timeout), 'network_max_retries': str(args_command_list.nb_retries), 'invalid_targets': {}} # Add the list of invalid targets for server_string, exception in invalid_servers_list: if isinstance(exception, ServerConnectivityError): json_output['invalidTargets'][server_string] = exception.error_msg else: # Unexpected bug in SSLyze raise exception # Add the output of the plugins for each server for host_str, plugin_result_list in result_dict.iteritems(): server_info = plugin_result_list[0].server_info json_output[host_str] = _format_json_result(server_info, plugin_result_list) final_json_output = json.dumps(json_output, default=lambda o: o.__dict__, sort_keys=True, indent=4) if args_command_list.json_file == '-': # Print XML output to the console if needed print final_json_output else: # Otherwise save the XML output to the console with open(args_command_list.json_file, 'w') as json_file: json_file.write(final_json_output) # Output XML doc to a file if needed if args_command_list.xml_file: result_xml_attr = {'totalScanTime': str(exec_time), 'networkTimeout': str(args_command_list.timeout), 'networkMaxRetries': str(args_command_list.nb_retries)} result_xml = Element('results', attrib = result_xml_attr) # Sort results in alphabetical order to make the XML files (somewhat) diff-able xml_output_list.sort(key=lambda xml_elem: xml_elem.attrib['host']) for xml_element in xml_output_list: result_xml.append(xml_element) xml_final_doc = Element('document', title="SSLyze Scan Results", SSLyzeVersion=__version__, SSLyzeWeb=PROJECT_URL) # Add the list of invalid targets invalid_targets_xml = Element('invalidTargets') for server_string, exception in invalid_servers_list: if isinstance(exception, ServerConnectivityError): error_xml = Element('invalidTarget', error=exception.error_msg) error_xml.text = server_string invalid_targets_xml.append(error_xml) else: # Unexpected bug in SSLyze raise exception xml_final_doc.append(invalid_targets_xml) # Add the output of the plugins xml_final_doc.append(result_xml) # Remove characters that are illegal for XML # https://lsimons.wordpress.com/2011/03/17/stripping-illegal-characters-out-of-xml-in-python/ xml_final_string = tostring(xml_final_doc, encoding='UTF-8') illegal_xml_chars_RE = re.compile(u'[\x00-\x08\x0b\x0c\x0e-\x1F\uD800-\uDFFF\uFFFE\uFFFF]') xml_sanitized_final_string = illegal_xml_chars_RE.sub('', xml_final_string) # Hack: Prettify the XML file so it's (somewhat) diff-able xml_final_pretty = minidom.parseString(xml_sanitized_final_string).toprettyxml(indent=" ", encoding="utf-8" ) if args_command_list.xml_file == '-': # Print XML output to the console if needed print xml_final_pretty else: # Otherwise save the XML output to the console with open(args_command_list.xml_file, 'w') as xml_file: xml_file.write(xml_final_pretty) if should_print_text_results: print _format_title('Scan Completed in {0:.2f} s'.format(exec_time))
def main(): # For py2exe builds freeze_support() # Handle SIGINT to terminate processes signal.signal(signal.SIGINT, sigint_handler) start_time = time() # Retrieve available plugins sslyze_plugins = PluginsFinder() available_plugins = sslyze_plugins.get_plugins() available_commands = sslyze_plugins.get_commands() # Create the command line parser and the list of available options sslyze_parser = CommandLineParser(available_plugins, __version__) try: good_server_list, bad_server_list, args_command_list = sslyze_parser.parse_command_line() except CommandLineParsingError as e: print e.get_error_msg() return output_hub = OutputHub() output_hub.command_line_parsed(available_plugins, args_command_list) # Initialize the pool of processes that will run each plugin if args_command_list.https_tunnel: # Maximum one process to not kill the proxy plugins_process_pool = PluginsProcessPool(sslyze_plugins, args_command_list.nb_retries, args_command_list.timeout, max_processes_nb=1) else: plugins_process_pool = PluginsProcessPool(sslyze_plugins, args_command_list.nb_retries, args_command_list.timeout) # Figure out which hosts are up and fill the task queue with work to do connectivity_tester = ServersConnectivityTester(good_server_list) connectivity_tester.start_connectivity_testing(network_timeout=args_command_list.timeout) # Store and print server whose command line string was bad for failed_scan in bad_server_list: output_hub.server_connectivity_test_failed(failed_scan) # Store and print servers we were able to connect to online_servers_list = [] for server_connectivity_info in connectivity_tester.get_reachable_servers(): online_servers_list.append(server_connectivity_info) output_hub.server_connectivity_test_succeeded(server_connectivity_info) # Send tasks to worker processes for plugin_command in available_commands: if getattr(args_command_list, plugin_command): # Get this plugin's options if there's any plugin_options_dict = {} for option in available_commands[plugin_command].get_interface().get_options(): # Was this option set ? if getattr(args_command_list,option.dest): plugin_options_dict[option.dest] = getattr(args_command_list, option.dest) plugins_process_pool.queue_plugin_task(server_connectivity_info, plugin_command, plugin_options_dict) # Store and print servers we were NOT able to connect to for tentative_server_info, exception in connectivity_tester.get_invalid_servers(): failed_scan = FailedServerScan(tentative_server_info.server_string, exception) output_hub.server_connectivity_test_failed(failed_scan) # Keep track of how many tasks have to be performed for each target task_num = 0 output_hub.scans_started() for command in available_commands: if getattr(args_command_list, command): task_num += 1 # Each host has a list of results result_dict = {} # We cannot use the server_info object directly as its address will change due to multiprocessing RESULT_KEY_FORMAT = u'{hostname}:{ip_address}:{port}'.format for server_info in online_servers_list: result_dict[RESULT_KEY_FORMAT(hostname=server_info.hostname, ip_address=server_info.ip_address, port=server_info.port)] = [] # Process the results as they come for plugin_result in plugins_process_pool.get_results(): server_info = plugin_result.server_info result_dict[RESULT_KEY_FORMAT(hostname=server_info.hostname, ip_address=server_info.ip_address, port=server_info.port)].append(plugin_result) plugin_result_list = result_dict[RESULT_KEY_FORMAT(hostname=server_info.hostname, ip_address=server_info.ip_address, port=server_info.port)] if len(plugin_result_list) == task_num: # Done with this server; send the result to the output hub output_hub.server_scan_completed(CompletedServerScan(server_info, plugin_result_list)) # All done exec_time = time()-start_time output_hub.scans_completed(exec_time)
def main(): # For py2exe builds freeze_support() # Handle SIGINT to terminate processes signal.signal(signal.SIGINT, sigint_handler) start_time = time() #--PLUGINS INITIALIZATION-- sslyze_plugins = PluginsFinder() available_plugins = sslyze_plugins.get_plugins() available_commands = sslyze_plugins.get_commands() # Create the command line parser and the list of available options sslyze_parser = CommandLineParser(available_plugins, __version__) online_servers_list = [] invalid_servers_list = [] # Parse the command line try: good_server_list, bad_server_list, args_command_list = sslyze_parser.parse_command_line( ) invalid_servers_list.extend(bad_server_list) except CommandLineParsingError as e: print e.get_error_msg() return should_print_text_results = not args_command_list.quiet and args_command_list.xml_file != '-' \ and args_command_list.json_file != '-' if should_print_text_results: print '\n\n\n' + _format_title('Available plugins') for plugin in available_plugins: print ' ' + plugin.__name__ print '\n\n' #--PROCESSES INITIALIZATION-- if args_command_list.https_tunnel: # Maximum one process to not kill the proxy plugins_process_pool = PluginsProcessPool(sslyze_plugins, args_command_list.nb_retries, args_command_list.timeout, max_processes_nb=1) else: plugins_process_pool = PluginsProcessPool(sslyze_plugins, args_command_list.nb_retries, args_command_list.timeout) #--TESTING SECTION-- # Figure out which hosts are up and fill the task queue with work to do if should_print_text_results: print _format_title('Checking host(s) availability') connectivity_tester = ServersConnectivityTester(good_server_list) connectivity_tester.start_connectivity_testing( network_timeout=args_command_list.timeout) SERVER_OK_FORMAT = u' {host}:{port:<25} => {ip_address} {client_auth_msg}' SERVER_INVALID_FORMAT = u' {server_string:<35} => WARNING: {error_msg}; discarding corresponding tasks.' # Store and print servers we were able to connect to for server_connectivity_info in connectivity_tester.get_reachable_servers( ): online_servers_list.append(server_connectivity_info) if should_print_text_results: client_auth_msg = '' client_auth_requirement = server_connectivity_info.client_auth_requirement if client_auth_requirement == ClientAuthenticationServerConfigurationEnum.REQUIRED: client_auth_msg = ' WARNING: Server REQUIRED client authentication, specific plugins will fail.' elif client_auth_requirement == ClientAuthenticationServerConfigurationEnum.OPTIONAL: client_auth_msg = ' WARNING: Server requested optional client authentication' print SERVER_OK_FORMAT.format( host=server_connectivity_info.hostname, port=server_connectivity_info.port, ip_address=server_connectivity_info.ip_address, client_auth_msg=client_auth_msg) # Send tasks to worker processes for plugin_command in available_commands: if getattr(args_command_list, plugin_command): # Get this plugin's options if there's any plugin_options_dict = {} for option in available_commands[plugin_command].get_interface( ).get_options(): # Was this option set ? if getattr(args_command_list, option.dest): plugin_options_dict[option.dest] = getattr( args_command_list, option.dest) plugins_process_pool.queue_plugin_task( server_connectivity_info, plugin_command, plugin_options_dict) for tentative_server_info, exception in connectivity_tester.get_invalid_servers( ): invalid_servers_list.append( (tentative_server_info.server_string, exception)) # Print servers we were NOT able to connect to if should_print_text_results: for server_string, exception in invalid_servers_list: if isinstance(exception, ServerConnectivityError): print SERVER_INVALID_FORMAT.format( server_string=server_string, error_msg=exception.error_msg) else: # Unexpected bug in SSLyze raise exception print '\n\n' # Keep track of how many tasks have to be performed for each target task_num = 0 for command in available_commands: if getattr(args_command_list, command): task_num += 1 # --REPORTING SECTION-- # XML output xml_output_list = [] # Each host has a list of results result_dict = {} # We cannot use the server_info object directly as its address will change due to multiprocessing RESULT_KEY_FORMAT = u'{hostname}:{ip_address}:{port}'.format for server_info in online_servers_list: result_dict[RESULT_KEY_FORMAT(hostname=server_info.hostname, ip_address=server_info.ip_address, port=server_info.port)] = [] # Process the results as they come for plugin_result in plugins_process_pool.get_results(): server_info = plugin_result.server_info result_dict[RESULT_KEY_FORMAT( hostname=server_info.hostname, ip_address=server_info.ip_address, port=server_info.port)].append(plugin_result) result_list = result_dict[RESULT_KEY_FORMAT( hostname=server_info.hostname, ip_address=server_info.ip_address, port=server_info.port)] if len(result_list) == task_num: # Done with this server; print the results and update the xml doc if args_command_list.xml_file: xml_output_list.append( _format_xml_target_result(server_info, result_list)) if should_print_text_results: print _format_txt_target_result(server_info, result_list) # --TERMINATE-- exec_time = time() - start_time # Output JSON to a file if needed if args_command_list.json_file: json_output = { 'total_scan_time': str(exec_time), 'network_timeout': str(args_command_list.timeout), 'network_max_retries': str(args_command_list.nb_retries), 'invalid_targets': [], 'accepted_targets': [] } # Add the list of invalid targets for server_string, exception in invalid_servers_list: if isinstance(exception, ServerConnectivityError): json_output['invalid_targets'].append( {server_string: exception.error_msg}) else: # Unexpected bug in SSLyze raise exception # Add the output of the plugins for each server for host_str, plugin_result_list in result_dict.iteritems(): server_info = plugin_result_list[0].server_info json_output['accepted_targets'].append( _format_json_result(server_info, plugin_result_list)) final_json_output = json.dumps(json_output, default=lambda o: o.__dict__, sort_keys=True, indent=4) if args_command_list.json_file == '-': # Print XML output to the console if needed print final_json_output else: # Otherwise save the XML output to the console with open(args_command_list.json_file, 'w') as json_file: json_file.write(final_json_output) # Output XML doc to a file if needed if args_command_list.xml_file: result_xml_attr = { 'totalScanTime': str(exec_time), 'networkTimeout': str(args_command_list.timeout), 'networkMaxRetries': str(args_command_list.nb_retries) } result_xml = Element('results', attrib=result_xml_attr) # Sort results in alphabetical order to make the XML files (somewhat) diff-able xml_output_list.sort(key=lambda xml_elem: xml_elem.attrib['host']) for xml_element in xml_output_list: result_xml.append(xml_element) xml_final_doc = Element('document', title="SSLyze Scan Results", SSLyzeVersion=__version__, SSLyzeWeb=PROJECT_URL) # Add the list of invalid targets invalid_targets_xml = Element('invalidTargets') for server_string, exception in invalid_servers_list: if isinstance(exception, ServerConnectivityError): error_xml = Element('invalidTarget', error=exception.error_msg) error_xml.text = server_string invalid_targets_xml.append(error_xml) else: # Unexpected bug in SSLyze raise exception xml_final_doc.append(invalid_targets_xml) # Add the output of the plugins xml_final_doc.append(result_xml) # Remove characters that are illegal for XML # https://lsimons.wordpress.com/2011/03/17/stripping-illegal-characters-out-of-xml-in-python/ xml_final_string = tostring(xml_final_doc, encoding='UTF-8') illegal_xml_chars_RE = re.compile( u'[\x00-\x08\x0b\x0c\x0e-\x1F\uD800-\uDFFF\uFFFE\uFFFF]') xml_sanitized_final_string = illegal_xml_chars_RE.sub( '', xml_final_string) # Hack: Prettify the XML file so it's (somewhat) diff-able xml_final_pretty = minidom.parseString( xml_sanitized_final_string).toprettyxml(indent=" ", encoding="utf-8") if args_command_list.xml_file == '-': # Print XML output to the console if needed print xml_final_pretty else: # Otherwise save the XML output to the console with open(args_command_list.xml_file, 'w') as xml_file: xml_file.write(xml_final_pretty) if should_print_text_results: print _format_title('Scan Completed in {0:.2f} s'.format(exec_time))
def main(): global global_scanner # For py2exe builds freeze_support() # Handle SIGINT to terminate processes signal.signal(signal.SIGINT, sigint_handler) start_time = time() plugins_repository = PluginsRepository() available_plugins = plugins_repository.get_available_plugins() available_commands = plugins_repository.get_available_commands() # Create the command line parser and the list of available options sslyze_parser = CommandLineParser(available_plugins, __version__) try: good_server_list, bad_server_list, args_command_list = sslyze_parser.parse_command_line() except CommandLineParsingError as e: print(e.get_error_msg()) return output_hub = OutputHub() output_hub.command_line_parsed(available_plugins, args_command_list) # Initialize the pool of processes that will run each plugin if args_command_list.https_tunnel: # Maximum one process to not kill the proxy global_scanner = ConcurrentScanner(args_command_list.nb_retries, args_command_list.timeout, max_processes_nb=1) else: global_scanner = ConcurrentScanner(args_command_list.nb_retries, args_command_list.timeout) # Figure out which hosts are up and fill the task queue with work to do connectivity_tester = ServersConnectivityTester(good_server_list) connectivity_tester.start_connectivity_testing(network_timeout=args_command_list.timeout) # Store and print server whose command line string was bad for failed_scan in bad_server_list: output_hub.server_connectivity_test_failed(failed_scan) # Store and print servers we were able to connect to online_servers_list = [] for server_connectivity_info in connectivity_tester.get_reachable_servers(): online_servers_list.append(server_connectivity_info) output_hub.server_connectivity_test_succeeded(server_connectivity_info) # Send tasks to worker processes for scan_command_class in available_commands: if getattr(args_command_list, scan_command_class.get_cli_argument()): # Get this command's optional argument if there's any optional_args = {} for optional_arg_name in scan_command_class.get_optional_arguments(): # Was this option set ? if getattr(args_command_list, optional_arg_name): optional_args[optional_arg_name] = getattr(args_command_list, optional_arg_name) scan_command = scan_command_class(**optional_args) global_scanner.queue_scan_command(server_connectivity_info, scan_command) # Store and print servers we were NOT able to connect to for tentative_server_info, exception in connectivity_tester.get_invalid_servers(): failed_scan = FailedServerScan(tentative_server_info.server_string, exception) output_hub.server_connectivity_test_failed(failed_scan) # Keep track of how many tasks have to be performed for each target task_num = 0 output_hub.scans_started() for scan_command_class in available_commands: if getattr(args_command_list, scan_command_class.get_cli_argument()): task_num += 1 # Each host has a list of results result_dict = {} # We cannot use the server_info object directly as its address will change due to multiprocessing RESULT_KEY_FORMAT = '{hostname}:{ip_address}:{port}' for server_info in online_servers_list: result_dict[RESULT_KEY_FORMAT.format(hostname=server_info.hostname, ip_address=server_info.ip_address, port=server_info.port)] = [] # Process the results as they come for plugin_result in global_scanner.get_results(): server_info = plugin_result.server_info result_dict[RESULT_KEY_FORMAT.format(hostname=server_info.hostname, ip_address=server_info.ip_address, port=server_info.port)].append(plugin_result) plugin_result_list = result_dict[RESULT_KEY_FORMAT.format(hostname=server_info.hostname, ip_address=server_info.ip_address, port=server_info.port)] if len(plugin_result_list) == task_num: # Done with this server; send the result to the output hub output_hub.server_scan_completed(CompletedServerScan(server_info, plugin_result_list)) # All done exec_time = time()-start_time output_hub.scans_completed(exec_time)