Skip to content

Commit

Permalink
Add: log_message, error_message, security_message
Browse files Browse the repository at this point in the history
Adds the possibility to store results within a Storage and adds the
builtin functions:
- log_message,
- error_message,
- security_message
  • Loading branch information
nichtsfrei committed Jul 23, 2024
1 parent 605a03d commit 7b78eeb
Show file tree
Hide file tree
Showing 12 changed files with 335 additions and 9 deletions.
1 change: 1 addition & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions rust/json-storage/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,9 @@ where
) -> Result<Box<dyn Iterator<Item = storage::Field>>, StorageError> {
Ok(match scope {
// currently not supported
storage::Retrieve::NVT(_) | storage::Retrieve::NotusAdvisory(_) => {
Box::new([].into_iter())
}
storage::Retrieve::NVT(_)
| storage::Retrieve::NotusAdvisory(_)
| storage::Retrieve::Result(_) => Box::new([].into_iter()),
storage::Retrieve::KB(s) => Box::new({
let kbs = self.kbs.lock().map_err(StorageError::from)?;
let kbs = kbs.clone();
Expand Down
1 change: 1 addition & 0 deletions rust/models/src/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ pub struct Result {
feature = "serde_support",
serde(skip_serializing_if = "Option::is_none", default)
)]
/// Details are only set on status and can be ignored
pub detail: Option<Detail>,
}

Expand Down
2 changes: 1 addition & 1 deletion rust/nasl-builtin-knowledge-base/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ fn get_kb_item(register: &Register, c: &Context) -> Result<NaslValue, FunctionEr
.map(|r| {
r.into_iter()
.filter_map(|x| match x {
Field::NVT(_) | Field::NotusAdvisory(_) => None,
Field::NVT(_) | Field::NotusAdvisory(_) | Field::Result(_) => None,
Field::KB(kb) => Some(kb.value.into()),
})
.collect::<Vec<_>>()
Expand Down
1 change: 1 addition & 0 deletions rust/nasl-builtin-std/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ nasl-builtin-http = { version = "0.1.0", path = "../nasl-builtin-http" }
nasl-builtin-description = {path = "../nasl-builtin-description"}
nasl-builtin-misc = {path = "../nasl-builtin-misc"}
storage = {path = "../storage"}
models = { path = "../models" }
nasl-syntax = {path = "../nasl-syntax"}

# depend on c libraries and are considered unstable for now
Expand Down
3 changes: 3 additions & 0 deletions rust/nasl-builtin-std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use nasl_builtin_utils::{Context, NaslFunctionRegister, NaslVarRegister, Register};
use storage::{ContextKey, DefaultDispatcher};
mod array;
mod report_functions;

/// The description builtin function
///
Expand Down Expand Up @@ -70,13 +71,15 @@ impl nasl_builtin_utils::NaslFunctionExecuter for Std {
pub fn nasl_std_functions() -> nasl_builtin_utils::NaslFunctionRegister {
let mut builder = nasl_builtin_utils::NaslfunctionRegisterBuilder::new()
.push_register(Std)
.push_register(report_functions::Reporting::default())
.push_register(nasl_builtin_knowledge_base::KnowledgeBase)
.push_register(nasl_builtin_misc::Misc)
.push_register(nasl_builtin_string::NaslString)
.push_register(nasl_builtin_host::Host)
.push_register(nasl_builtin_http::NaslHttp::default())
.push_register(nasl_builtin_cryptographic::Cryptographic)
.push_register(nasl_builtin_description::Description);

builder = add_ssh(builder);
builder = add_raw_ip(builder);
builder.build()
Expand Down
130 changes: 130 additions & 0 deletions rust/nasl-builtin-std/src/report_functions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
use std::sync::{Arc, RwLock};

use models::{Protocol, ResultType};
use nasl_builtin_utils::{Context, ContextType, FunctionErrorKind, Register};
use nasl_syntax::NaslValue;

#[derive(Debug, Clone, Default)]
/// The description builtin function
pub struct Reporting {
id: Arc<RwLock<usize>>,
}

impl Reporting {
fn id(&self) -> usize {
let mut id = self.id.as_ref().write().expect("expected write lock");
let result = *id;
*id += 1;
result
}

fn store_result(
&self,
typus: ResultType,
register: &Register,
context: &Context,
) -> Result<NaslValue, FunctionErrorKind> {
let data = register.named("data").map(|x| x.to_string());
let port = register
.named("port")
.and_then(|x| match x {
ContextType::Value(x) => Some(x.into()),
_ => None,
})
.map(|x: i64| x as i16);

let protocol = match register
.named("proto")
.map(|x| x.to_string())
.as_ref()
.map(|x| x as &str)
{
Some("udp") => Protocol::UDP,
_ => Protocol::TCP,
};
// TOO: enhance id
let result = models::Result {
id: self.id(),
r_type: typus,
ip_address: Some(context.target().to_string()),
// TODO:
hostname: None,
oid: Some(context.key().value()),
port,
protocol: Some(protocol),
message: data,
detail: None,
};
context.dispatcher().retry_dispatch(
5,
context.key(),
storage::Field::Result(result.into()),
)?;
Ok(NaslValue::Null)
}

/// *void* **log_message**(data: *string*, port:*int* , proto: *string*, uri: *string*);
///
/// Creates a log result based on the given arguments
/// - data, is the text report
/// - port, optional TCP or UDP port number of the service
/// - proto is the protocol ("tcp" by default; "udp" is the other value).
/// - uri specifies the location of a found product
fn log_message(
&self,
register: &Register,
context: &Context,
) -> Result<NaslValue, FunctionErrorKind> {
self.store_result(ResultType::Log, register, context)
}

/// *void* **security_message**(data: *string*, port:*int* , proto: *string*, uri: *string*);
///
/// Creates a alarm result based on the given arguments
/// - data, is the text report
/// - port, optional TCP or UDP port number of the service
/// - proto is the protocol ("tcp" by default; "udp" is the other value).
/// - uri specifies the location of a found product
fn security_message(
&self,
register: &Register,
context: &Context,
) -> Result<NaslValue, FunctionErrorKind> {
self.store_result(ResultType::Alarm, register, context)
}

/// *void* **error_message**(data: *string*, port:*int* , proto: *string*, uri: *string*);
///
/// Creates a error result based on the given arguments
/// - data, is the text report
/// - port, optional TCP or UDP port number of the service
/// - proto is the protocol ("tcp" by default; "udp" is the other value).
/// - uri specifies the location of a found product
fn error_message(
&self,
register: &Register,
context: &Context,
) -> Result<NaslValue, FunctionErrorKind> {
self.store_result(ResultType::Error, register, context)
}
}

impl nasl_builtin_utils::NaslFunctionExecuter for Reporting {
fn nasl_fn_execute(
&self,
name: &str,
register: &Register,
context: &Context,
) -> Option<nasl_builtin_utils::NaslResult> {
match name {
"log_message" => Some(self.log_message(register, context)),
"security_message" => Some(self.security_message(register, context)),
"error_message" => Some(self.error_message(register, context)),
_ => None,
}
}

fn nasl_fn_defined(&self, name: &str) -> bool {
matches!(name, "log_message" | "security_message" | "error_message")
}
}
98 changes: 98 additions & 0 deletions rust/nasl-builtin-std/tests/log.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// SPDX-FileCopyrightText: 2023 Greenbone AG
//
// SPDX-License-Identifier: GPL-2.0-or-later WITH x11vnc-openssl-exception

#[cfg(test)]
mod tests {

use nasl_builtin_std::ContextFactory;
use nasl_builtin_utils::Register;
use nasl_interpreter::CodeInterpreter;

fn verify(function: &str, result_type: models::ResultType) {
let code = format!(
r###"
{function}(data: "test0", port: 12, proto: "udp", uri: "moep");
{function}(data: "test1", port: 12, proto: "tcp", uri: "moep");
{function}(data: "test2", port: 12, proto: "nonsense", uri: "moep");
{function}(data: "test3");
"###
);
let register = Register::default();
let binding = ContextFactory::default();
let context = binding.build(Default::default(), Default::default());

let mut parser = CodeInterpreter::new(&code, register, &context);
let no_error = parser.find_map(|x| x.err());
assert_eq!(
no_error, None,
"there should be no error when creating log_messages"
);
let results = context
.retriever()
.results(context.key())
.unwrap()
.collect::<Vec<_>>();
assert_eq!(
results.len(),
4,
"expected the same results as log_message calls"
);

let create_expected = |id, port, protocol| models::Result {
id,
r_type: result_type.clone(),
ip_address: Some(context.target().to_string()),
hostname: None,
oid: Some(context.key().value()),
port,
protocol: Some(protocol),
message: Some(format!("test{id}")),
detail: None,
};
let udp = context
.retriever()
.result(context.key(), 0)
.expect("expected udp result of first call")
.unwrap();
let expected = create_expected(0, Some(12), models::Protocol::UDP);
assert_eq!(udp, expected);

let tcp = context
.retriever()
.result(context.key(), 1)
.expect("expected udp result of first call")
.unwrap();
let expected = create_expected(1, Some(12), models::Protocol::TCP);
assert_eq!(tcp, expected);
let defaults_to_tcp = context
.retriever()
.result(context.key(), 2)
.expect("expected udp result of first call")
.unwrap();
let expected = create_expected(2, Some(12), models::Protocol::TCP);
assert_eq!(defaults_to_tcp, expected);
let default = context
.retriever()
.result(context.key(), 3)
.expect("expected udp result of first call")
.unwrap();
let expected = create_expected(3, None, models::Protocol::TCP);
assert_eq!(default, expected);
}

#[test]
fn log_message() {
verify("log_message", models::ResultType::Log)
}

#[test]
fn security_message() {
verify("security_message", models::ResultType::Alarm)
}

#[test]
fn error_message() {
verify("error_message", models::ResultType::Error)
}
}
6 changes: 3 additions & 3 deletions rust/redis-storage/src/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -734,9 +734,9 @@ where
scope: storage::Retrieve,
) -> Result<Box<dyn Iterator<Item = storage::Field>>, StorageError> {
Ok(match scope {
storage::Retrieve::NotusAdvisory(_) | storage::Retrieve::NVT(_) => {
Box::new(Vec::new().into_iter())
}
storage::Retrieve::NotusAdvisory(_)
| storage::Retrieve::NVT(_)
| storage::Retrieve::Result(_) => Box::new(Vec::new().into_iter()),
storage::Retrieve::KB(s) => Box::new({
let kbs = self.kbs.lock().map_err(StorageError::from)?;
let kbs = kbs.clone();
Expand Down
3 changes: 2 additions & 1 deletion rust/storage/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ impl Nvt {
NVTField::Nvt(x) => self == x,
NVTField::NoOp | NVTField::Version(_) => false,
},
Field::KB(_) | Field::NotusAdvisory(_) => false,
Field::KB(_) | Field::NotusAdvisory(_) | Field::Result(_) => false,
}
}
/// Verifies if a nvt is matching a field
Expand Down Expand Up @@ -918,6 +918,7 @@ where
Field::NVT(nvt) => self.store_nvt_field(nvt),
Field::KB(kb) => self.dispatcher.dispatch_kb(key, kb),
Field::NotusAdvisory(adv) => self.dispatcher.dispatch_advisory(key.as_ref(), *adv),
Field::Result(result) => self.dispatch(key, Field::Result(result)),
}
}

Expand Down
Loading

0 comments on commit 7b78eeb

Please sign in to comment.