Skip to content

Commit

Permalink
Add: preference handler module
Browse files Browse the repository at this point in the history
This module gets a scan config and prepare the data to be stored in redis as openvas-scanner expected.
The data is stored in redis as well. For that, a new module openvas_redis was added as well, which adds an implements
the RedisHelper struct.

Depends on #1566
  • Loading branch information
jjnicola committed Feb 12, 2024
1 parent f6396e9 commit 9119381
Show file tree
Hide file tree
Showing 11 changed files with 845 additions and 81 deletions.
165 changes: 91 additions & 74 deletions rust/Cargo.lock

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions rust/models/src/credential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub struct Credential {
#[cfg_attr(feature = "serde_support", serde(flatten))]
/// Type of the credential to get access. Different services support different types.
pub credential_type: CredentialType,

}

impl Credential {
Expand Down Expand Up @@ -75,12 +76,16 @@ pub enum Service {
#[cfg_attr(feature = "serde_support", serde(rename = "snmp"))]
/// SNMP, supports [SNMP](CredentialType::SNMP)
SNMP,
#[cfg_attr(feature = "serde_support", serde(rename = "privilege_ssh"))]
/// Privilege SSH, supports [SSH](CredentialType::UP)
PSSH,
}

impl AsRef<str> for Service {
fn as_ref(&self) -> &str {
match self {
Service::SSH => "ssh",
Service::PSSH => "privilege_ssh",
Service::SMB => "smb",
Service::ESXi => "esxi",
Service::SNMP => "snmp",
Expand Down
90 changes: 90 additions & 0 deletions rust/models/src/port.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,93 @@ impl TryFrom<&str> for Protocol {
}
}
}

pub fn ports_to_openvas_port_list(ports: Vec<Port>) -> Option<String> {

fn add_range_to_list (list: &mut String, start: usize, end: Option<usize>) {
// Add range
if let Some(end) = end {
list.push_str(start.to_string().as_str());
list.push('-');
list.push_str(end.to_string().as_str());
list.push(',');
// Add single port
} else {
list.push_str(start.to_string().as_str());
list.push(',');
}

}
if ports.is_empty() {
return None;
}

let mut udp = String::from("udp:");
let mut tcp = String::from("tcp:");

ports.iter().for_each(
|p| match p.protocol {
Some(Protocol::TCP) => {p.range.iter().for_each(|r| add_range_to_list(&mut tcp, r.start, r.end));},
Some(Protocol::UDP) => {p.range.iter().for_each(|r| add_range_to_list(&mut udp, r.start, r.end));},
None => {
p.range.iter().for_each(|r| add_range_to_list(&mut tcp, r.start, r.end));
p.range.iter().for_each(|r| add_range_to_list(&mut udp, r.start, r.end));
}
}
);
tcp.push_str(&udp);
Some(tcp)

}

#[cfg(test)]
mod tests {
use std::ptr::eq;

use crate::{Protocol, Port,PortRange, ports_to_openvas_port_list};

#[test]
fn test_port_convertion_to_string() {

let ports = vec![
Port{
protocol: Some(Protocol::TCP),
range: vec![
PortRange{
start: 22,
end: Some(25),
},
PortRange{
start: 80,
end: None,
},
]
},
Port{
protocol: Some(Protocol::UDP),
range: vec![
PortRange{
start: 30,
end: Some(40),
},
PortRange{
start: 5060,
end: None,
},
]
},
Port{
protocol: None,
range: vec![
PortRange{
start: 1000,
end: None,
},
]
},
];
assert_eq!(ports_to_openvas_port_list(ports), Some("tcp:22-25,80,1000,udp:30-40,5060,1000,".to_string()));

}
}

12 changes: 7 additions & 5 deletions rust/models/src/target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ use super::{credential::Credential, port::Port};
pub struct Target {
/// List of hosts to scan
pub hosts: Vec<String>,
/// List of excluded hosts to scan
pub excluded_hosts: Vec<String>,
/// List of ports used for scanning
pub ports: Vec<Port>,
#[cfg_attr(feature = "serde_support", serde(default))]
Expand Down Expand Up @@ -43,9 +45,9 @@ pub struct Target {
#[cfg_attr(feature = "bincode_support", derive(bincode::Encode, bincode::Decode))]
#[cfg_attr(feature = "serde_support", serde(rename_all = "snake_case"))]
pub enum AliveTestMethods {
Icmp,
TcpSyn,
TcpAck,
Arp,
ConsiderAlive,
Icmp = 0x01,
TcpSyn = 0x02,
TcpAck = 0x04,
Arp = 0x08,
ConsiderAlive = 0x16,
}
3 changes: 3 additions & 0 deletions rust/openvasctl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ edition = "2021"

[dependencies]
models = { path = "../models" }
redis = "0.22.0"
redis-storage = { version = "0.1.0", path = "../redis-storage" }
storage = { version = "0.1.0", path = "../storage" }
2 changes: 2 additions & 0 deletions rust/openvasctl/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
pub mod cmd;
pub mod ctl;
pub mod error;
pub mod openvas_redis;
pub mod pref_handler;
75 changes: 75 additions & 0 deletions rust/openvasctl/src/openvas_redis.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// SPDX-FileCopyrightText: 2024 Greenbone AG
//
// SPDX-License-Identifier: GPL-2.0-or-later

use redis_storage::{
dberror::{DbError, RedisStorageResult},
NameSpaceSelector, RedisCtx, RedisGetNvt, RedisWrapper,
};
use std::sync::{Arc, Mutex};
use storage::item::Nvt;

#[derive(Debug, Default)]
pub struct RedisHelper<R>
where
R: RedisWrapper,
{
cache: Arc<Mutex<R>>,
task_kb: Arc<Mutex<R>>,
}

impl RedisHelper<RedisCtx> {
/// Initialize a RedisHelper struct with the connection to access the NVT cache
/// and a empty task knowledge base to store the scan configuration to be sent to openvas.
pub fn init(
redis_url: &str,
selector: &[NameSpaceSelector],
) -> RedisStorageResult<RedisHelper<RedisCtx>> {
let mut rctx = RedisCtx::open(redis_url, selector)?;
rctx.delete_namespace()?;
let cache = RedisCtx::open(redis_url, selector)?;

Ok(RedisHelper::<RedisCtx> {
cache: Arc::new(Mutex::new(cache)),
task_kb: Arc::new(Mutex::new(rctx)),
})
}

/// Provide access to the cache
pub fn kb_id(&self) -> RedisStorageResult<u32> {
let cache = &self
.cache
.lock()
.map_err(|e| DbError::SystemError(format!("{e:?}")))?;
Ok(cache.db)
}
}

pub trait KbAccess {
fn push_kb_item<T: redis::ToRedisArgs>(&self, key: &str, value: T) -> RedisStorageResult<()>;
}

impl KbAccess for RedisHelper<RedisCtx> {
fn push_kb_item<T: redis::ToRedisArgs>(&self, key: &str, value: T) -> RedisStorageResult<()> {
let mut kb = Arc::as_ref(&self.task_kb)
.lock()
.map_err(|e| DbError::SystemError(format!("{e:?}")))?;

kb.lpush(key, value)?;
Ok(())
}
}

pub trait VtHelper {
fn get_vt(&self, oid: &str) -> RedisStorageResult<Option<Nvt>>;
}

impl VtHelper for RedisHelper<RedisCtx> {
fn get_vt(&self, oid: &str) -> RedisStorageResult<Option<Nvt>> {
let mut cache = Arc::as_ref(&self.cache)
.lock()
.map_err(|e| DbError::SystemError(format!("{e:?}")))?;

cache.redis_get_vt(oid)
}
}
Loading

0 comments on commit 9119381

Please sign in to comment.