diff --git a/doc/man/openvas.8.in b/doc/man/openvas.8.in index 70a1f20ec..afb2cd1a8 100644 --- a/doc/man/openvas.8.in +++ b/doc/man/openvas.8.in @@ -76,6 +76,9 @@ so you need to find a balance between these two options. Note that launching too .IP log_whole_attack If this option is set to 'yes', openvas will store the name, pid, date and target of each plugin launched. This is helpful for monitoring and debugging purpose, however this option might make openvas fill your disk rather quickly. +.IP report_scripts +Stores in a file the script run duration in json format. This option expects a valid path to store a file with scripts stats. Script run durations are collected only if the log_whole_attack setting is set to 'yes'. This is helpful for monitoring and debugging purpose, however this option might make openvas fill your disk rather quickly. + .IP debug_tls This is an scanner-only option which allows you to set the TLS log level. The level is an integer between 0 and 9. Higher values mean more verbosity and diff --git a/nasl/nasl_init.c b/nasl/nasl_init.c index e38a800fe..77eef99cb 100644 --- a/nasl/nasl_init.c +++ b/nasl/nasl_init.c @@ -79,6 +79,7 @@ static init_func libfuncs[] = { {"script_xref", script_xref}, {"script_tag", script_tag}, {"vendor_version", nasl_vendor_version}, + {"generate_host_stats", nasl_generate_host_stats}, {"update_table_driven_lsc_data", nasl_update_table_driven_lsc_data}, {"get_preference", nasl_get_preference}, {"safe_checks", safe_checks}, diff --git a/nasl/nasl_scanner_glue.c b/nasl/nasl_scanner_glue.c index 34abfe2a2..92faca729 100644 --- a/nasl/nasl_scanner_glue.c +++ b/nasl/nasl_scanner_glue.c @@ -1054,6 +1054,51 @@ nasl_get_preference (lex_ctxt *lexic) return retc; } +tree_cell * +nasl_generate_host_stats (lex_ctxt *lexic) +{ + tree_cell *retc; + struct script_infos *script_infos = lexic->script_infos; + kb_t kb = script_infos->key; + GString *data = g_string_new (""); + struct kb_item *stats = NULL, *stats_tmp = NULL; + int first = 1; + + stats = kb_item_get_pattern (kb, "general/script_stats*"); + stats_tmp = stats; + + g_string_append_c (data, '['); + while (stats_tmp) + { + char **spl = g_strsplit (stats_tmp->v_str, "/", 0); + char *buf = NULL; + + if (!first) + g_string_append_c (data, ','); + + buf = g_strdup_printf ("{\"%s\": {\"start\": %s, \"stop\": %s}}", spl[0], + spl[1], spl[2]); + + g_string_append (data, buf); + g_strfreev (spl); + g_free (buf); + + stats_tmp = stats_tmp->next; + if (first) + first = 0; + } + g_string_append_c (data, ']'); + + kb_item_free (stats); + + retc = alloc_typed_cell (CONST_STR); + retc->x.str_val = strdup (data->str); + retc->size = data->len; + g_string_free (data, TRUE); + + return retc; +} + tree_cell * nasl_vendor_version (lex_ctxt *lexic) { diff --git a/nasl/nasl_scanner_glue.h b/nasl/nasl_scanner_glue.h index 113efb9f9..4fa7b4e4c 100644 --- a/nasl/nasl_scanner_glue.h +++ b/nasl/nasl_scanner_glue.h @@ -118,4 +118,7 @@ nasl_vendor_version (lex_ctxt *); tree_cell * nasl_update_table_driven_lsc_data (lex_ctxt *); +tree_cell * +nasl_generate_host_stats (lex_ctxt *); + #endif diff --git a/src/attack.c b/src/attack.c index b3d1cc1fb..d063000f0 100644 --- a/src/attack.c +++ b/src/attack.c @@ -44,6 +44,7 @@ #include /* for nvticache_t */ #include #include +#include #include /* for strlen() */ #include /* for waitpid() */ #include /* for close() */ @@ -702,6 +703,7 @@ attack_host (struct scan_globals *globals, struct in6_addr *ip, pluginlaunch_stop (); plugins_scheduler_free (args->sched); host_set_time (get_main_kb (), ip_str, "HOST_END"); + write_host_stats (args->host_kb, globals->scan_id, ip_str); } /* @@ -1355,6 +1357,13 @@ attack_network (struct scan_globals *globals) alive_hosts_list = gvm_hosts_new (gvm_host_value_str (host)); } + if (prefs_get ("report_scripts")) + { + char *path = g_strdup_printf ( + "%s/%s-stats.json", prefs_get ("report_scripts"), globals->scan_id); + write_script_stats ("{\"hosts\": {", path, 2); + g_free (path); + } /* * Start the attack ! */ @@ -1545,15 +1554,31 @@ attack_network (struct scan_globals *globals) gettimeofday (&now, NULL); if (test_alive_hosts_only) - g_message ("Vulnerability scan %s finished in %ld seconds: " - "%d alive hosts of %d", - globals->scan_id, now.tv_sec - then.tv_sec, - gvm_hosts_count (alive_hosts_list), gvm_hosts_count (hosts)); + { + g_message ("Vulnerability scan %s finished in %ld seconds: " + "%d alive hosts of %d", + globals->scan_id, now.tv_sec - then.tv_sec, + gvm_hosts_count (alive_hosts_list), gvm_hosts_count (hosts)); + } else g_message ("Vulnerability scan %s finished in %ld seconds: %d hosts", globals->scan_id, now.tv_sec - then.tv_sec, gvm_hosts_count (hosts)); + if (prefs_get ("report_scripts")) + { + char *buff = + g_strdup_printf ("},\"scan_time\": {\"start\": %ld, \"stop\": %ld}}", + then.tv_sec, now.tv_sec); + char *path = g_strdup_printf ( + "%s/%s-stats.json", prefs_get ("report_scripts"), globals->scan_id); + + write_script_stats (buff, globals->scan_id, 1); + + g_free (buff); + g_free (path); + } + gvm_hosts_free (hosts); if (alive_hosts_list) gvm_hosts_free (alive_hosts_list); diff --git a/src/pluginlaunch.c b/src/pluginlaunch.c index 25880f99d..b054d7c72 100644 --- a/src/pluginlaunch.c +++ b/src/pluginlaunch.c @@ -183,6 +183,7 @@ update_running_processes (kb_t main_kb, kb_t kb) processes[i].start.tv_sec++; now.tv_usec += 1000000; } + if (log_whole) { char *name = nvticache_get_filename (oid); @@ -193,6 +194,14 @@ update_running_processes (kb_t main_kb, kb_t kb) (long) ((now.tv_usec - processes[i].start.tv_usec) / 1000)); g_free (name); + + char msg[2048]; + g_snprintf (msg, sizeof (msg), "%s/%ld/%ld", oid, + (long) ((now.tv_sec * 1000) + + (long) (now.tv_usec / 1000)), + (long) (processes[i].start.tv_sec * 1000 + + processes[i].start.tv_usec / 1000)); + kb_item_push_str (kb, "general/script_stats", msg); } now = old_now; do diff --git a/src/utils.c b/src/utils.c index 1d2f9a481..41af22a86 100644 --- a/src/utils.c +++ b/src/utils.c @@ -14,14 +14,17 @@ #include "../misc/plugutils.h" /* for kb_item_set_int_with_main_kb_check */ #include "../misc/scanneraux.h" /* for struct scan_globals */ +#include "base/networking.h" -#include /* for errno() */ +#include /* for errno() */ +#include #include /* for prefs_get() */ #include /* for is_host_alive() */ -#include /* for atoi() */ -#include /* for strcmp() */ -#include /* for ioctl() */ -#include /* for waitpid() */ +#include +#include /* for atoi() */ +#include /* for strcmp() */ +#include /* for ioctl() */ +#include /* for waitpid() */ extern int global_max_hosts; extern int global_max_checks; @@ -254,3 +257,94 @@ is_scanner_only_pref (const char *pref) return 1; return 0; } + +/** @brief Writes scripts stats into a file. + * + * @param buf String to write. + * @param path Path to the file to write into. + * @param mode 2 to create the file, 0 to append text to the file, + * 1 to finish the json list removing the trailing comma before + * appending the last text in the buffer. + * + */ +void +write_script_stats (const char *buf, const char *path, int mode) +{ + FILE *pd = NULL; + + if (mode < 0 || mode > 2) + { + g_warning ("%s: invalid mode %d", __func__, mode); + return; + } + pd = fopen (path, mode == 0 ? "a" : mode == 1 ? "r+" : "w"); + if (pd == NULL) + { + g_warning ("%s: Error opening FILE for script stats: %d - %s", __func__, + errno, strerror (errno)); + return; + } + + if (mode == 1) + { + int ch; + while ((ch = fgetc (pd)) != EOF) + ; + fseek (pd, -1, SEEK_CUR); + } + fprintf (pd, "%s", buf); + fflush (pd); + fclose (pd); +} + +/** @brief Reads the script stats from the kb and generate a string in json + format to be stored in the disk. + * + * @param kb the host knowledge base to get the information from. + * @param scan_id Scan ID for the file name. + * @param ip target IP address. + */ +void +write_host_stats (kb_t kb, const char *scan_id, const char *ip) +{ + GString *data = g_string_new (""); + struct kb_item *stats = NULL, *stats_tmp = NULL; + int firstvt = 1; + char *path = NULL; + + if (!prefs_get ("report_scripts")) + return; + + stats = kb_item_get_pattern (kb, "general/script_stats*"); + stats_tmp = stats; + + g_string_append_printf (data, "\"%s\": [", ip); + while (stats_tmp) + { + char **spl = g_strsplit (stats_tmp->v_str, "/", 0); + char *buf = NULL; + + if (!firstvt) + g_string_append_c (data, ','); + + buf = g_strdup_printf ("{\"%s\": {\"start\": %s, \"stop\": %s}}", spl[0], + spl[1], spl[2]); + + g_string_append (data, buf); + g_strfreev (spl); + g_free (buf); + + stats_tmp = stats_tmp->next; + if (firstvt) + firstvt = 0; + } + g_string_append (data, "],"); + + path = + g_strdup_printf ("%s/%s-stats.json", prefs_get ("report_scripts"), scan_id); + + kb_item_free (stats); + write_script_stats (data->str, path, 0); + g_free (path); + g_string_free (data, TRUE); +} diff --git a/src/utils.h b/src/utils.h index c63a7b691..c47ecdbcb 100644 --- a/src/utils.h +++ b/src/utils.h @@ -40,4 +40,10 @@ store_file (struct scan_globals *globals, const char *file, int check_host_still_alive (kb_t, const char *); + +void +write_script_stats (const char *, const char *, int); + +void +write_host_stats (kb_t, const char *, const char *); #endif