Skip to content
Draft
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
32 changes: 26 additions & 6 deletions rust/src/nasl/builtin/description/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,32 @@ pub fn script_tag(ctx: &ScanCtx, name: &str, value: &NaslValue) -> Result<(), Fn
Ok(())
}

#[nasl_function(named(name, value))]
pub fn script_xref(ctx: &ScanCtx, name: String, value: String) {
ctx.nvt_mut().as_mut().unwrap().references.push(NvtRef {
class: name,
id: value,
});
#[nasl_function(named(name, value, csv))]
pub fn script_xref(
ctx: &ScanCtx,
name: String,
value: Option<String>,
csv: Option<String>,
) -> Result<(), FnError> {
if value.is_none() && csv.is_none() {
return Err(FnError::missing_argument("value or csv"));
}

let mut nvt = ctx.nvt_mut();
let references = &mut nvt.as_mut().unwrap().references;
if let Some(csv) = csv {
references.extend(csv.split(',').map(|id| NvtRef {
class: name.clone(),
id: id.to_owned(),
}));
}
if let Some(value) = value {
references.push(NvtRef {
class: name,
id: value,
});
}
Ok(())
}

#[nasl_function(named(name, value, id, r#type))]
Expand Down
5 changes: 5 additions & 0 deletions rust/src/nasl/builtin/misc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,11 @@ impl DefineGlobalVars for Misc {
),
("NASL_ERR_EUNREACH", NaslValue::Number(NASL_ERR_EUNREACH)),
("NASL_ERR_EUNKNOWN", NaslValue::Number(NASL_ERR_EUNKNOWN)),
("NOERR", NaslValue::Number(NASL_ERR_NOERR)),
("ETIMEDOUT", NaslValue::Number(NASL_ERR_ETIMEDOUT)),
("ECONNRESET", NaslValue::Number(NASL_ERR_ECONNRESET)),
("EUNREACH", NaslValue::Number(NASL_ERR_EUNREACH)),
("EUNKNOWN", NaslValue::Number(NASL_ERR_EUNKNOWN)),
]
}
}
1 change: 1 addition & 0 deletions rust/src/nasl/builtin/network/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1412,6 +1412,7 @@ function_set! {
impl DefineGlobalVars for SocketFns {
fn get_global_vars() -> Vec<(&'static str, NaslValue)> {
vec![
("MSG_OOB", NaslValue::Number(libc::MSG_OOB.into())),
("ENCAPS_AUTO", NaslValue::Number(OpenvasEncaps::Auto.into())),
("ENCAPS_IP", NaslValue::Number(OpenvasEncaps::Ip.into())),
(
Expand Down
4 changes: 4 additions & 0 deletions rust/src/nasl/builtin/raw_ip/packet_forgery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3373,6 +3373,10 @@ impl DefineGlobalVars for PacketForgery {
"IPPROTO_ICMP",
NaslValue::Number(IpNextHeaderProtocols::Icmp.to_primitive_values().0.into()),
),
(
"IPPROTO_ICMPV6",
NaslValue::Number(IpNextHeaderProtocols::Icmpv6.to_primitive_values().0.into()),
),
(
"IPPROTO_IGMP",
NaslValue::Number(IpNextHeaderProtocols::Igmp.to_primitive_values().0.into()),
Expand Down
25 changes: 25 additions & 0 deletions rust/src/nasl/builtin/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,37 @@
//! It would be nicer to have this within the proc_macro crate itself,
//! but testing proc_macros comes with a lot of difficulties and the tests
//! are very easy to do here.
use std::collections::HashMap;

use crate::nasl::{
builtin::misc::{
NASL_ERR_ECONNRESET, NASL_ERR_ETIMEDOUT, NASL_ERR_EUNKNOWN, NASL_ERR_EUNREACH,
NASL_ERR_NOERR,
},
nasl_std_executor,
test_prelude::*,
utils::{Executor, ScanCtx},
};

#[test]
fn standard_executor_has_c_compatible_globals() {
let executor = nasl_std_executor();
let globals = executor.iter_fn_global_vars().collect::<HashMap<_, _>>();
let expected = [
("IPPROTO_ICMPV6", 58),
("MSG_OOB", libc::MSG_OOB.into()),
("NOERR", NASL_ERR_NOERR),
("ETIMEDOUT", NASL_ERR_ETIMEDOUT),
("ECONNRESET", NASL_ERR_ECONNRESET),
("EUNREACH", NASL_ERR_EUNREACH),
("EUNKNOWN", NASL_ERR_EUNKNOWN),
];

for (name, value) in expected {
assert_eq!(globals.get(name), Some(&NaslValue::Number(value)), "{name}");
}
}

#[nasl_function]
fn foo1(_ctx: &ScanCtx, x: usize) -> usize {
x
Expand Down
14 changes: 13 additions & 1 deletion rust/src/nasl/syntax/grammar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use super::{
};
use crate::nasl::{
error::{Span, Spanned},
syntax::token::{Ident, Literal, TokenKind},
syntax::token::{Ident, Literal, LiteralKind, TokenKind},
};

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -219,6 +219,18 @@ pub enum Atom {
Increment(Increment),
}

impl Atom {
pub fn as_string_literal(&self) -> Option<&str> {
match self {
Self::Literal(Literal {
kind: LiteralKind::String(value),
..
}) => Some(value),
_ => None,
}
}
}

#[derive(Clone, Debug)]
pub struct Array {
pub items: CommaSeparated<Expr, Bracket>,
Expand Down
2 changes: 1 addition & 1 deletion rust/src/nasl/syntax/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ pub use token::{Ident, Token};
pub use tokenizer::CharIndex;
pub use tokenizer::Tokenizer;
pub use tokenizer::TokenizerError;
pub use visitor::{Visitor, walk_ast};
pub use visitor::{Visitor, walk_ast, walk_block};
17 changes: 15 additions & 2 deletions rust/src/nasl/syntax/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@ pub trait Visitor<'ast> {
fn visit_statement(&mut self, _stmt: &'ast Statement) {}
fn visit_var_scope_decl(&mut self, _decl: &'ast VarScopeDecl) {}
fn visit_fn_decl(&mut self, _decl: &'ast FnDecl) {}
fn should_walk_fn_body(&self, _decl: &'ast FnDecl) -> bool {
true
}
fn visit_block(&mut self, _block: &'ast Block<Statement>) {}
fn visit_while(&mut self, _while_stmt: &'ast While) {}
fn visit_repeat(&mut self, _repeat: &'ast Repeat) {}
fn visit_for_each(&mut self, _for_each: &'ast ForEach) {}
fn visit_for_each_binding(&mut self, _for_each: &'ast ForEach) {}
fn visit_for(&mut self, _for_stmt: &'ast For) {}
fn visit_if(&mut self, _if_stmt: &'ast If) {}
fn visit_include(&mut self, _include: &'ast Include) {}
Expand All @@ -22,13 +26,16 @@ pub trait Visitor<'ast> {
fn visit_binary(&mut self, _binary: &'ast Binary) {}
fn visit_unary(&mut self, _unary: &'ast Unary) {}
fn visit_assignment(&mut self, _assignment: &'ast Assignment) {}
fn leave_assignment(&mut self, _assignment: &'ast Assignment) {}

// Atom visitors
fn visit_atom(&mut self, _atom: &'ast Atom) {}
fn visit_array(&mut self, _array: &'ast Array) {}
fn visit_array_access(&mut self, _access: &'ast ArrayAccess) {}
fn visit_fn_call(&mut self, _call: &'ast FnCall) {}
fn leave_fn_call(&mut self, _call: &'ast FnCall) {}
fn visit_increment(&mut self, _inc: &'ast Increment) {}
fn leave_increment(&mut self, _inc: &'ast Increment) {}
fn visit_literal(&mut self, _literal: &'ast super::super::syntax::token::Literal) {}
fn visit_ident(&mut self, _ident: &'ast super::super::syntax::token::Ident) {}

Expand Down Expand Up @@ -63,7 +70,7 @@ fn walk_statement<'ast, V: Visitor<'ast>>(visitor: &mut V, stmt: &'ast Statement
}
}

fn walk_block<'ast, V: Visitor<'ast>>(visitor: &mut V, block: &'ast Block<Statement>) {
pub fn walk_block<'ast, V: Visitor<'ast>>(visitor: &mut V, block: &'ast Block<Statement>) {
visitor.visit_block(block);
for stmt in &block.items {
walk_statement(visitor, stmt);
Expand All @@ -86,6 +93,7 @@ fn walk_for_each<'ast, V: Visitor<'ast>>(visitor: &mut V, for_each: &'ast ForEac
visitor.visit_for_each(for_each);
visitor.visit_ident(&for_each.var);
walk_expr(visitor, &for_each.array);
visitor.visit_for_each_binding(for_each);
walk_block(visitor, &for_each.block);
}

Expand Down Expand Up @@ -130,7 +138,9 @@ fn walk_fn_decl<'ast, V: Visitor<'ast>>(visitor: &mut V, fn_decl: &'ast FnDecl)
for arg in &fn_decl.args.items {
visitor.visit_ident(arg);
}
walk_block(visitor, &fn_decl.block);
if visitor.should_walk_fn_body(fn_decl) {
walk_block(visitor, &fn_decl.block);
}
}

fn walk_var_scope_decl<'ast, V: Visitor<'ast>>(visitor: &mut V, var_decl: &'ast VarScopeDecl) {
Expand Down Expand Up @@ -169,6 +179,7 @@ fn walk_assignment<'ast, V: Visitor<'ast>>(visitor: &mut V, assignment: &'ast As
visitor.visit_assignment(assignment);
walk_place_expr(visitor, &assignment.lhs);
walk_expr(visitor, &assignment.rhs);
visitor.leave_assignment(assignment);
}

fn walk_place_expr<'ast, V: Visitor<'ast>>(visitor: &mut V, place: &'ast PlaceExpr) {
Expand Down Expand Up @@ -213,6 +224,7 @@ fn walk_fn_call<'ast, V: Visitor<'ast>>(visitor: &mut V, call: &'ast FnCall) {
for arg in &call.args.items {
walk_fn_arg(visitor, arg);
}
visitor.leave_fn_call(call);
}

fn walk_fn_arg<'ast, V: Visitor<'ast>>(visitor: &mut V, arg: &'ast FnArg) {
Expand All @@ -229,4 +241,5 @@ fn walk_fn_arg<'ast, V: Visitor<'ast>>(visitor: &mut V, arg: &'ast FnArg) {
fn walk_increment<'ast, V: Visitor<'ast>>(visitor: &mut V, inc: &'ast Increment) {
visitor.visit_increment(inc);
walk_place_expr(visitor, &inc.expr);
visitor.leave_increment(inc);
}
5 changes: 5 additions & 0 deletions rust/src/nasl/utils/executor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ impl Executor {
self.fn_global_vars.iter().cloned()
}

/// Names of global variables supplied by registered builtin function sets.
pub fn iter_global_var_names(&self) -> impl Iterator<Item = &str> {
self.fn_global_vars.iter().map(|(name, _)| *name)
}

pub fn iter(&self) -> impl Iterator<Item = &str> {
self.sets.iter().flat_map(|set| set.iter())
}
Expand Down
40 changes: 38 additions & 2 deletions rust/src/scannerctl/linter/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use scannerlib::nasl::Loader;

#[derive(clap::Parser)]
pub struct LinterArgs {
/// Either a single NASL file or a directory of NASL files on which to run the linter.
/// Either a single NASL file or a feed directory. Directory scans use
/// `.nasl` files as roots and load `.inc` files through include statements.
pub path: PathBuf,
}

Expand All @@ -17,11 +18,46 @@ pub(super) fn get_files_and_loader(root: &Path) -> Result<(Loader, Vec<PathBuf>)
} else {
for e in walkdir::WalkDir::new(root) {
let e = e.map_err(std::io::Error::from)?;
if let Some("nasl") | Some("inc") = e.path().extension().and_then(|ext| ext.to_str()) {
if e.path().extension().and_then(|ext| ext.to_str()) == Some("nasl") {
files.push(e.path().strip_prefix(root).unwrap().to_owned());
}
}
files.sort();
Loader::from_feed_path(root)
};
Ok((loader, files))
}

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

use super::*;

#[test]
fn directory_uses_only_nasl_files_as_roots() {
let directory = tempfile::tempdir().unwrap();
fs::write(directory.path().join("first.nasl"), "").unwrap();
fs::write(directory.path().join("second.nasl"), "").unwrap();
fs::write(directory.path().join("functions.inc"), "").unwrap();

let (_, mut files) = get_files_and_loader(directory.path()).unwrap();
files.sort();

assert_eq!(
files,
vec![PathBuf::from("first.nasl"), PathBuf::from("second.nasl")]
);
}

#[test]
fn explicit_include_file_is_still_a_root() {
let directory = tempfile::tempdir().unwrap();
let include = directory.path().join("functions.inc");
fs::write(&include, "").unwrap();

let (_, files) = get_files_and_loader(&include).unwrap();

assert_eq!(files, vec![PathBuf::from("functions.inc")]);
}
}
Loading
Loading