Skip to content

Commit

Permalink
use a target struct which supports vhosts instead of a string as Cont…
Browse files Browse the repository at this point in the history
…ext member.

Also, add more host built-in functions
  • Loading branch information
jjnicola committed Nov 14, 2024
1 parent 19e5c95 commit 792305d
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 24 deletions.
6 changes: 3 additions & 3 deletions rust/src/feed/update/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::nasl::interpreter::{CodeInterpreter, Interpreter};
use crate::nasl::nasl_std_functions;
use crate::nasl::prelude::*;
use crate::nasl::syntax::AsBufReader;
use crate::nasl::utils::context::Target;
use crate::nasl::ContextType;
use crate::storage::{item::NVTField, ContextKey, Dispatcher, NoOpRetriever};

Expand Down Expand Up @@ -48,7 +49,7 @@ pub async fn feed_version(
let register = Register::default();
let k = ContextKey::default();
let fr = NoOpRetriever::default();
let target = String::default();
let target = Target::default();
// TODO add parameter to struct
let functions = nasl_std_functions();
let context = Context::new(k, target, dispatcher, &fr, loader, &functions);
Expand Down Expand Up @@ -147,9 +148,8 @@ where

let register = Register::root_initial(&self.initial);
let fr = NoOpRetriever::default();
let target = String::default();
let target = Target::default();
let functions = nasl_std_functions();

let context = Context::new(
key.clone(),
target,
Expand Down
98 changes: 86 additions & 12 deletions rust/src/nasl/builtin/host/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@
mod tests;

use std::{
net::{IpAddr, SocketAddr, ToSocketAddrs},
str::FromStr,
env::var_os, net::{IpAddr, SocketAddr, ToSocketAddrs}, str::FromStr
};

use dns_lookup::lookup_addr;

use crate::function_set;
use crate::{function_set, models::Source};
use crate::nasl::utils::{error::FunctionErrorKind, lookup_keys::TARGET};

use crate::nasl::syntax::NaslValue;
Expand Down Expand Up @@ -52,9 +51,9 @@ fn get_host_names(register: &Register, _: &Context) -> Result<NaslValue, Functio
///
/// As of now (2023-01-20) there is no vhost handling.
/// Therefore this function does load the registered TARGET and if it is an IP Address resolves it via DNS instead.
fn get_host_name(register: &Register, _: &Context) -> Result<NaslValue, FunctionErrorKind> {
resolve_hostname(register).map(NaslValue::String)
}
//fn get_host_name(register: &Register, _: &Context) -> Result<NaslValue, FunctionErrorKind> {
// resolve_hostname(register).map(NaslValue::String)
//}

/// Return the target's IP address as IpAddr.
pub fn get_host_ip(context: &Context) -> Result<IpAddr, FunctionErrorKind> {
Expand All @@ -73,6 +72,80 @@ pub fn get_host_ip(context: &Context) -> Result<IpAddr, FunctionErrorKind> {
}
}

pub fn add_host_name (
register: &Register,
context: &Context,
) -> Result<NaslValue, FunctionErrorKind> {
let hostname = match register.named("hostname") {
Some(ContextType::Value(NaslValue::String(x))) if !x.is_empty() => x.clone(),
_ => {
return Err(FunctionErrorKind::diagnostic_ret_null("Empty Hostname"));
}
};
let source = match register.named("source") {
Some(ContextType::Value(NaslValue::String(x))) if !x.is_empty() => x.clone(),
_ => "NASL".to_string()
};

context.add_hostname(hostname, source);
Ok(NaslValue::Null)
}


pub fn get_host_name (
_register: &Register,
context: &Context,
) -> Result<NaslValue, FunctionErrorKind> {
let mut v = Vec::new();
if let Some(vh) = context.target_vhosts() {
v = vh.into_iter().map(|(v,_s)| NaslValue::String(v)).collect::<Vec<_>>();
}

if !v.is_empty() {
return Ok(NaslValue::Fork(v));
}


if let Ok(ip) = get_host_ip(context) {
match lookup_addr(&ip) {
Ok(host) => Ok(NaslValue::String(host)),
Err(_) => Ok(NaslValue::String(ip.to_string()))
}
} else {
Ok(NaslValue::String(context.target().to_string()))
}
}


pub fn get_host_name_source (
register: &Register,
context: &Context,
) -> Result<NaslValue, FunctionErrorKind> {
let hostname = match register.named("hostname") {
Some(ContextType::Value(NaslValue::String(x))) if !x.is_empty() => x.clone(),
_ => {
return Err(FunctionErrorKind::diagnostic_ret_null("Empty Hostname"));
}
};


if let Some(vh) = context.target_vhosts() {
if let Some(source) = vh.into_iter()
.find_map(|(v,s)| {
if v == hostname {
Some(s)
} else {
None
}
}) {
return Ok(NaslValue::String(source));
};
}

Ok(NaslValue::Null)

}

/// Return the target's IP address or 127.0.0.1 if not set.
fn nasl_get_host_ip(
_register: &Register,
Expand Down Expand Up @@ -175,6 +248,9 @@ fn target_is_ipv6(_register: &Register, context: &Context) -> Result<NaslValue,
}
}

/// Compare if two hosts are the same.
/// The first two unnamed arguments are string containing the host to compare
/// If the named argument cmp_hostname is set to TRUE, the given hosts are resolved into their hostnames
fn same_host(register: &Register, _: &Context) -> Result<NaslValue, FunctionErrorKind> {
let positional = register.positional();
if positional.len() != 2 {
Expand Down Expand Up @@ -255,11 +331,7 @@ fn same_host(register: &Register, _: &Context) -> Result<NaslValue, FunctionErro
}
}

if flag {
Ok(NaslValue::Boolean(true))
} else {
Ok(NaslValue::Boolean(false))
}
Ok(NaslValue::Boolean(flag))
}

pub struct Host;
Expand All @@ -274,6 +346,8 @@ function_set! {
resolve_host_name,
resolve_hostname_to_multiple_ips,
(target_is_ipv6, "TARGET_IS_IPV6"),
same_host
same_host,
add_host_name,
get_host_name_source
)
}
7 changes: 5 additions & 2 deletions rust/src/nasl/builtin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ use crate::nasl::syntax::{Loader, NoOpLoader};
use crate::nasl::utils::{Context, Executor, NaslVarRegister, NaslVarRegisterBuilder, Register};
use crate::storage::{ContextKey, DefaultDispatcher, Storage};

use super::utils::context::Target;

/// Creates a new Executor and adds all the functions to it.
///
/// When you have a function that is considered experimental due to either dependencies on
Expand Down Expand Up @@ -135,11 +137,12 @@ where

/// Creates a new Context with the shared loader, logger and function register
pub fn build(&self, key: ContextKey) -> Context {
let target = match &key {
let mut target = Target::default();
target.set_target(match &key {
ContextKey::Scan(_, Some(target)) => target.clone(),
ContextKey::Scan(_, None) => String::default(),
ContextKey::FileName(target) => target.clone(),
};
});
Context::new(
key,
target,
Expand Down
71 changes: 68 additions & 3 deletions rust/src/nasl/utils/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,8 @@ impl Default for Register {
}
}
use std::collections::HashMap;
use std::net::IpAddr;
use std::sync::Mutex;
type Named = HashMap<String, ContextType>;

/// NaslContext is a struct to contain variables and if root declared functions
Expand Down Expand Up @@ -328,6 +330,46 @@ impl NaslContext {
}
}

#[derive(Debug,Default)]
pub struct Target {

/// The original target. IP or hostname
target: String,
/// The IP address
ip_addr: String,
// The shared state is guarded by a mutex. This is a `std::sync::Mutex` and
// not a Tokio mutex. This is because there are no asynchronous operations
// being performed while holding the mutex. Additionally, the critical
// sections are very small.
//
// A Tokio mutex is mostly intended to be used when locks need to be held
// across `.await` yield points. All other cases are **usually** best
// served by a std mutex. If the critical section does not include any
// async operations but is long (CPU intensive or performing blocking
// operations), then the entire operation, including waiting for the mutex,
// is considered a "blocking" operation and `tokio::task::spawn_blocking`
// should be used.
/// vhost list which resolve to the IP address and their sources.
vhosts: Mutex<Vec<(String, String)>>
}

impl Target {
pub fn set_target (&mut self, target: String) -> &Target{
self.target = target;
self
}

pub fn add_hostname (&self, hostname: String, source: String) -> &Target{
self.vhosts.lock().unwrap().push((hostname, source));
self
}

pub fn add_ipaddress (&mut self, ip: IpAddr ) -> &Target{
self.ip_addr = ip.to_string();
self
}
}

/// Configurations
///
/// This struct includes all objects that a nasl function requires.
Expand All @@ -336,7 +378,7 @@ pub struct Context<'a> {
/// key for this context. A file name or a scan id
key: ContextKey,
/// target to run a scan against
target: String,
target: Target,
/// Default Dispatcher
dispatcher: &'a dyn Dispatcher,
/// Default Retriever
Expand All @@ -351,7 +393,7 @@ impl<'a> Context<'a> {
/// Creates an empty configuration
pub fn new(
key: ContextKey,
target: String,
target: Target,
dispatcher: &'a dyn Dispatcher,
retriever: &'a dyn Retriever,
loader: &'a dyn Loader,
Expand Down Expand Up @@ -395,9 +437,32 @@ impl<'a> Context<'a> {

/// Get the target host
pub fn target(&self) -> &str {
&self.target
&self.target.target
}

/// Get the target IP address list
pub fn target_ipaddr(&self) -> Option<String> {
Some(self.target.ip_addr.clone())
}

/// Get the target VHost list
pub fn target_vhosts(&self) -> Option<Vec<(String, String)>> {
Some(self.target.vhosts.lock().unwrap().clone())
}

pub fn set_target (&mut self, target: String) {
self.target.target = target;
}

pub fn add_hostname (&self, hostname: String, source: String) {
self.target.add_hostname(hostname, source);
}

pub fn add_ipaddress (&mut self, ip: IpAddr ) {
self.target.add_ipaddress(ip);

}

/// Get the storage
pub fn dispatcher(&self) -> &dyn Dispatcher {
self.dispatcher
Expand Down
2 changes: 1 addition & 1 deletion rust/src/nasl/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub mod lookup_keys;

use std::collections::HashMap;

pub use context::{Context, ContextType, Register};
pub use context::{Context, ContextType, Register, Target};
pub use error::FunctionErrorKind;

pub use executor::{Executor, IntoFunctionSet, StoredFunctionSet};
Expand Down
3 changes: 2 additions & 1 deletion rust/src/scanner/scan_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ pub(super) mod tests {
use crate::models::Target;
use crate::models::VT;
use crate::nasl::syntax::NaslValue;
use crate::nasl::utils::Target as ContextTarget;
use crate::nasl::utils::Context;
use crate::nasl::utils::Executor;
use crate::nasl::utils::Register;
Expand Down Expand Up @@ -320,7 +321,7 @@ exit({rc});
let storage = DefaultDispatcher::new();

let register = Register::root_initial(&initial);
let target = String::default();
let target = ContextTarget::default();
let functions = nasl_std_functions();
let loader = |_: &str| code.to_string();
let key = ContextKey::FileName(id.to_string());
Expand Down
7 changes: 5 additions & 2 deletions rust/src/scanner/vt_runner.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::models::{Host, Parameter, Protocol, ScanId};
use crate::nasl::syntax::{Loader, NaslValue};
use crate::nasl::utils::context::Target;
use crate::nasl::utils::{Executor, Register};
use crate::scheduling::Stage;
use crate::storage::item::Nvt;
Expand Down Expand Up @@ -193,10 +194,12 @@ impl<'a, Stack: ScannerStack> VTRunner<'a, Stack> {
if let Err(e) = self.check_keys(self.vt) {
return e;
}

let mut target = Target::default();
target.set_target(self.target.clone());

let context = Context::new(
self.generate_key(),
self.target.clone(),
target,
self.storage.as_dispatcher(),
self.storage.as_retriever(),
self.loader,
Expand Down

0 comments on commit 792305d

Please sign in to comment.