Skip to content

Commit

Permalink
Add: script run duration stats per host (#1774)
Browse files Browse the repository at this point in the history
* Add: script run duration stats per host
For testing, run the following script.
Stats are collected only if the log_whole_attack scanner preference is set.
Later, the script must run to generate the result.

```

if(description)
{
  script_oid("1.3.6.1.4.1.25623.1.200.1");
  script_version("2024-11-29T13:05:23+0000");
  script_tag(name:"last_modification", value:"2024-11-29 13:05:23 +0000 (Fri, 29 Nov 2024)");
  script_tag(name:"creation_date", value:"2024-11-29 13:05:23 +0100 (Fri, 29 Nov 2024)");
  script_tag(name:"cvss_base_vector", value:"AV:N/AC:L/Au:N/C:N/I:N/A:N");
  script_tag(name:"cvss_base", value:"0.0");
  script_name("Script Stats");
  script_copyright("Copyright (C) 2024 Greenbone AG");
  script_family("Service detection");
  # nb: Needs to run at the end of the scan because of the required info only available in this phase...
  script_category(ACT_END);
  script_tag(name:"summary", value:"This scripts logs the run duration of the scripts.");

  script_timeout(3600);
  exit(0);
}

log_message( data: generate_host_stats() );
exit( 0 );
```

* Add: report_scripts openvas setting

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'.

For testing, set the setting in openvas.conf with a valid path and set log_whole_attack setting to yes.
A json file will be created containing script run duration for each host as json objects.
  • Loading branch information
jjnicola authored Jan 10, 2025
1 parent 69838a9 commit 9678b81
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 9 deletions.
3 changes: 3 additions & 0 deletions doc/man/openvas.8.in
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions nasl/nasl_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down
45 changes: 45 additions & 0 deletions nasl/nasl_scanner_glue.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
3 changes: 3 additions & 0 deletions nasl/nasl_scanner_glue.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
33 changes: 29 additions & 4 deletions src/attack.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include <gvm/util/nvticache.h> /* for nvticache_t */
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <string.h> /* for strlen() */
#include <sys/wait.h> /* for waitpid() */
#include <unistd.h> /* for close() */
Expand Down Expand Up @@ -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);
}

/*
Expand Down Expand Up @@ -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 !
*/
Expand Down Expand Up @@ -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);
Expand Down
9 changes: 9 additions & 0 deletions src/pluginlaunch.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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
Expand Down
104 changes: 99 additions & 5 deletions src/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 <errno.h> /* for errno() */
#include <errno.h> /* for errno() */
#include <fcntl.h>
#include <gvm/base/prefs.h> /* for prefs_get() */
#include <gvm/boreas/cli.h> /* for is_host_alive() */
#include <stdlib.h> /* for atoi() */
#include <string.h> /* for strcmp() */
#include <sys/ioctl.h> /* for ioctl() */
#include <sys/wait.h> /* for waitpid() */
#include <stdio.h>
#include <stdlib.h> /* for atoi() */
#include <string.h> /* for strcmp() */
#include <sys/ioctl.h> /* for ioctl() */
#include <sys/wait.h> /* for waitpid() */

extern int global_max_hosts;
extern int global_max_checks;
Expand Down Expand Up @@ -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);
}
6 changes: 6 additions & 0 deletions src/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 9678b81

Please sign in to comment.