Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change: progress information #1832

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 17 additions & 8 deletions rust/doc/faq/progress-calculation.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,33 @@ You get a json object which looks like as following:
"alive": 1,
"queued": 0,
"finished": 1,
"scanning": [
"127.0.0.1": 12,
"127.0.0.3": 75,
]
"scanning": {
"127.0.0.1": {
finished_tests: 10,
total_tests: 20
},
"127.0.0.3": {
finished_tests: 12,
total_tests: 20
}
}
}
}
```

Then, with this information you can calculate the scan progress with the following suggested formula:

```
scan_progress = (sum_of_scanning_hosts_values + 100 * finished)
for host in scanning {
sum_of_scanning_hosts_progress += 100 * finished_tests / total_tests
}
scan_progress = (sum_of_scanning_hosts_progress + 100 * finished)
/ (all - dead)
```
For the example given above, the progress is:

```
scan_progress = (12 + 75 + 100 * 1) / (12 - 2) = 18.7 %
scan_progress = (50 + 60 + 100 * 1) / (12 - 2) = 18.7 %
```

## Special case for resume task
Expand All @@ -54,8 +63,8 @@ At the beginning of the resumed scan you have:
"alive": 1,
"queued": 0,
"finished": 1,
"scanning": [
]
"scanning": {
}
}
}

Expand Down
55 changes: 42 additions & 13 deletions rust/doc/openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -895,10 +895,7 @@ components:
type: "integer"
format: "int32"
scanning:
description: "The IP Addresses of the currently scanned hosts."
type: "array"
items:
type: "string"
$ref: "#/components/schemas/Scanning"

required:
- all
Expand All @@ -908,6 +905,30 @@ components:
- queued
- finished

SingleHostProgress: {
type: "object",
description: "Additional information about the scanned host",
properties: {
finished_tests: {
description: "The number of vulnerability tests already run for the host",
type: "integer",
format: "int32"
},
total_tests: {
description: "The total amount of vulnerability tests to be run for the host",
type: "integer",
format: "int32"
}
}
}

Scanning:
description: "The IP Addresses of the currently scanned hosts."
type: "object"
additionalProperties: {
$ref: "#/components/schemas/SingleHostProgress"
}

ScanAction:
description: "An action to perform on a scan"
type: "object"
Expand Down Expand Up @@ -1228,16 +1249,24 @@ components:
{
"start_time": 1679649183,
"status": "running",
"host_info":
{
"all": 14,
"excluded": 0,
"dead": 4,
"alive": 6,
"queued": 1,
"finished": 1,
"scanning": ["127.0.0.1", "10.0.5.1", "10.0.5.2", "10.0.5.3"],
"host_info": {
"all": 14,
"excluded": 0,
"dead": 4,
"alive": 6,
"queued": 1,
"finished": 1,
"scanning": {
"192.168.0.1": {
"finished_tests": 456,
"total_tests": 1000
},
"192.168.0.2": {
"finished_tests": 456,
"total_tests": 1000
}
},
},
}

scan_status_success:
Expand Down
63 changes: 57 additions & 6 deletions rust/src/models/host_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub struct HostInfoBuilder {
pub alive: u64,
pub queued: u64,
pub finished: u64,
pub scanning: Option<HashMap<String, i32>>,
pub scanning: Option<HashMap<String, SingleHostScanInfo>>,
}

impl HostInfoBuilder {
Expand All @@ -32,6 +32,58 @@ impl HostInfoBuilder {
}
}

#[derive(Default, Debug, Clone, Eq, PartialEq)]
#[cfg_attr(
feature = "serde_support",
derive(serde::Serialize, serde::Deserialize)
)]
pub struct SingleHostScanInfo {
finished_tests: AmountOfTests,
total_tests: AmountOfTests,
}

#[derive(Debug, Clone, Eq, PartialEq)]
#[cfg_attr(
feature = "serde_support",
derive(serde::Serialize, serde::Deserialize)
)]
enum AmountOfTests {
AmountOfTests(i32),
DeadHost,
}

impl Default for AmountOfTests {
fn default() -> Self {
AmountOfTests::AmountOfTests(0)
}
}

impl SingleHostScanInfo {
pub fn new(finished_tests: i32, total_tests: i32) -> Self {
Self {
finished_tests: AmountOfTests::AmountOfTests(finished_tests),
total_tests: if total_tests == -1 {
AmountOfTests::DeadHost
} else {
AmountOfTests::AmountOfTests(total_tests)
},
}
}

pub fn is_finished(&self) -> bool {
if let AmountOfTests::AmountOfTests(f) = self.finished_tests {
if let AmountOfTests::AmountOfTests(t) = self.total_tests {
return f == t;
}
}
false
}

pub fn is_dead(&self) -> bool {
matches!(self.total_tests, AmountOfTests::DeadHost)
}
}

/// Information about hosts of a running scan
#[derive(Debug, Clone, Default, PartialEq, Eq)]
#[cfg_attr(
Expand All @@ -51,9 +103,8 @@ pub struct HostInfo {
feature = "serde_support",
serde(skip_serializing_if = "Option::is_none")
)]
scanning: Option<HashMap<String, i32>>,
// Hosts that are currently being scanned. The second entry is the number of
// remaining VTs for this host.
scanning: Option<HashMap<String, SingleHostScanInfo>>,
#[cfg_attr(feature = "serde_support", serde(skip))]
remaining_vts_per_host: HashMap<String, usize>,
}

Expand Down Expand Up @@ -112,10 +163,10 @@ impl HostInfo {
// and never completely replaced.
let mut hs = other.scanning.clone().unwrap_or_default();
for (host, progress) in self.scanning.clone().unwrap_or_default().iter() {
if *progress == 100 || *progress == -1 {
if progress.is_finished() || progress.is_dead() {
hs.remove(host);
} else {
hs.insert(host.to_string(), *progress);
hs.insert(host.to_string(), progress.clone());
}
}
self.scanning = Some(hs);
Expand Down
52 changes: 30 additions & 22 deletions rust/src/openvas/result_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ use std::{
sync::{Arc, Mutex},
};

use crate::openvas::openvas_redis::{KbAccess, VtHelper};
use crate::osp::{OspResultType, OspScanResult};
use crate::storage::redis::RedisStorageResult;
use crate::{
models::SingleHostScanInfo,
openvas::openvas_redis::{KbAccess, VtHelper},
};

/// Structure to hold the results retrieve from redis main kb
#[derive(Default, Debug, Clone)]
Expand All @@ -30,7 +33,7 @@ pub struct Results {
/// during the scan
pub count_dead: i64,
/// Current hosts status
pub host_status: HashMap<String, i32>,
pub host_status: HashMap<String, SingleHostScanInfo>,
/// The scan status
pub scan_status: String,
}
Expand Down Expand Up @@ -135,11 +138,12 @@ where
} else if result_type == "ALARM" {
push_result(OspResultType::Alarm);
} else if result_type == "DEADHOST" {
new_dead += i64::from_str(&value).expect("Valid amount of dead hosts");
new_dead += i64::from_str(&value).expect("Expected a valid amount of dead hosts");
} else if host_count {
count_total = i64::from_str(&value).expect("Valid amount of dead hosts");
count_total = i64::from_str(&value).expect("Expected a valid amount of dead hosts");
} else if excluded_hosts {
count_excluded = i64::from_str(&value).expect("Valid amount of excluded hosts");
count_excluded =
i64::from_str(&value).expect("Expected a valid amount of excluded hosts");
}
}
if let Ok(mut results) = Arc::as_ref(&self.results).lock() {
Expand All @@ -160,37 +164,40 @@ where
}

fn process_status(&self, redis_status: Vec<String>) -> RedisStorageResult<()> {
enum ScanProgress {
DeadHost = -1,
}
let mut new_dead = 0;
let mut new_alive = 0;
let mut all_hosts: HashMap<String, i32> = HashMap::new();
let mut all_hosts: HashMap<String, SingleHostScanInfo> = HashMap::new();
for res in redis_status {
let mut fields = res.splitn(3, '/');
let current_host = fields.next().expect("Valid status value");
let launched = fields.next().expect("Valid status value");
let total = fields.next().expect("Valid status value");
let current_host = fields.next().expect("Expected a valid status value");
let launched = fields.next().expect("Expected a valid status value");
let total = fields.next().expect("Expected a valid status value");

let host_progress: i32 = match i32::from_str(total) {
let total = match i32::from_str(total) {
// No plugins
Ok(0) => {
continue;
}
// Host Dead
Ok(-1) => ScanProgress::DeadHost as i32,
Ok(n) => ((f32::from_str(launched).expect("Integer") / n as f32) * 100.0) as i32,
Ok(-1) => -1,
Ok(n) => n,
_ => {
continue;
}
};

if host_progress == -1 {
let launched = i32::from_str(launched).expect("Expected a valid integer value");
let host_progress = ((launched as f32 / total as f32) * 100.0) as i32;
if total == -1 {
new_dead += 1;
} else if host_progress == 100 {
new_alive += 1;
}
all_hosts.insert(current_host.to_string(), host_progress);

all_hosts.insert(
current_host.to_string(),
SingleHostScanInfo::new(launched, total),
);

tracing::debug!("Host {} has progress: {}", current_host, host_progress);
}
Expand Down Expand Up @@ -225,6 +232,7 @@ mod tests {

use crate::models::{self, Protocol, Result, ResultType};
use crate::openvas::openvas_redis::FakeRedis;
use crate::openvas::result_collector::SingleHostScanInfo;
use std::collections::HashMap;

use super::ResultHelper;
Expand Down Expand Up @@ -346,11 +354,11 @@ mod tests {
resh.process_status(status).unwrap();

let mut r = HashMap::new();
r.insert("127.0.0.1".to_string(), 12);
r.insert("127.0.0.3".to_string(), 75);
r.insert("127.0.0.4".to_string(), 100);
r.insert("127.0.0.2".to_string(), -1);
r.insert("127.0.0.5".to_string(), -1);
r.insert("127.0.0.1".to_string(), SingleHostScanInfo::new(128, 1000));
r.insert("127.0.0.3".to_string(), SingleHostScanInfo::new(750, 1000));
r.insert("127.0.0.4".to_string(), SingleHostScanInfo::new(1000, 1000));
r.insert("127.0.0.2".to_string(), SingleHostScanInfo::new(0, -1));
r.insert("127.0.0.5".to_string(), SingleHostScanInfo::new(0, -1));

assert_eq!(resh.results.as_ref().lock().unwrap().host_status, r);
assert_eq!(resh.results.as_ref().lock().unwrap().count_alive, 1);
Expand Down
6 changes: 4 additions & 2 deletions rust/src/osp/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use std::{collections::HashMap, fmt};

use serde::{de::Visitor, Deserialize};

use crate::models::SingleHostScanInfo;

use super::commands::Error;

/// StringU32 is a wrapper around u32 to allow deserialization of strings
Expand Down Expand Up @@ -602,10 +604,10 @@ impl From<Scan> for crate::models::Status {
ScanStatus::Interrupted => crate::models::Phase::Failed,
};

let mut scanning: HashMap<String, i32> = HashMap::new();
let mut scanning: HashMap<String, SingleHostScanInfo> = HashMap::new();
if let Some(i) = &value.host_info {
for host in &i.host {
scanning.insert(host.name.clone(), 0);
scanning.insert(host.name.clone(), SingleHostScanInfo::new(0, 0));
}
}
crate::models::Status {
Expand Down
Loading