Skip to content

Commit

Permalink
Add: webserver for HTTP API (#1385)
Browse files Browse the repository at this point in the history
This commit contains a webserver, which was specified within the OpenAPI specification. It's components are:
- A webserver serving als the new API implementation using the rocket framework
- A model module, containing all JSON models used for the API
- Default implementations for the Scan- and VT-Management for testing purposes
- Error handling
- A Request guard and catcher for json parsing errors
  • Loading branch information
Kraemii committed May 2, 2023
1 parent e3e7be6 commit 8eb9234
Show file tree
Hide file tree
Showing 29 changed files with 2,415 additions and 37 deletions.
1,087 changes: 1,050 additions & 37 deletions rust/Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ members = [
"json-storage",
"feed",
"feed-verifier",
"scanner-api",
"models"
]
11 changes: 11 additions & 0 deletions rust/models/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "models"
version = "0.1.0"
edition = "2021"
license = "GPL-2.0-or-later"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
serde = {version = "1", features = ["derive"]}
serde_json = "1"
70 changes: 70 additions & 0 deletions rust/models/src/json/credential.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use serde::{Deserialize, Serialize};

/// Represents a set of credentials to be used for scanning to access a host.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Credential {
/// Service to use for accessing a host
pub service: Service,
/// Port used for getting access. If missing a standard port is used
pub port: Option<u16>,
#[serde(flatten)]
/// Type of the credential to get access. Different services support different types.
pub credential_type: CredentialType,
}

/// Enum of available services
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Service {
#[serde(rename = "ssh")]
/// SSH, supports [UP](CredentialType::UP) and [USK](CredentialType::USK) as credential types
SSH,
#[serde(rename = "smb")]
/// SMB, supports [UP](CredentialType::UP)
SMB,
#[serde(rename = "esxi")]
/// ESXi, supports [UP](CredentialType::UP)
ESXi,
#[serde(rename = "snmp")]
/// SNMP, supports [SNMP](CredentialType::SNMP)
SNMP,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
/// Enum representing the type of credentials.
pub enum CredentialType {
#[serde(rename = "up")]
/// User/password credentials.
UP {
/// The username for authentication.
username: String,
/// The password for authentication.
password: String,
},
#[serde(rename = "usk")]
/// User/ssh-key credentials.
USK {
/// The username for authentication.
username: String,
/// The password for authentication.
password: String,
#[serde(rename = "private")]
/// The private key for authentication.
private_key: String,
},
#[serde(rename = "snmp")]
/// SNMP credentials.
SNMP {
/// The SNMP username.
username: String,
/// The SNMP password.
password: String,
/// The SNMP community string.
community: String,
/// The SNMP authentication algorithm.
auth_algorithm: String,
/// The SNMP privacy password.
privacy_password: String,
/// The SNMP privacy algorithm.
privacy_algorithm: String,
},
}
21 changes: 21 additions & 0 deletions rust/models/src/json/host_info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use serde::{Deserialize, Serialize};

/// Information about hosts of a running scan
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct HostInfo {
/// Number of all hosts, that are contained in a target
pub all: i32,
/// Number of hosts, that are excluded from the target
pub excluded: i32,
/// Number of hosts, that are not reachable (alive-test failed)
pub dead: i32,
/// Number of hosts, that are reachable (alive-test succeeded)
pub alive: i32,
/// Number of hosts, that are currently queued for scanning
pub queued: i32,
/// Number of hosts, that are already finished scanning
pub finished: i32,
#[serde(skip_serializing_if = "Option::is_none")]
/// IPs of hosts, that are currently scanned.
pub scanning: Option<Vec<String>>,
}
153 changes: 153 additions & 0 deletions rust/models/src/json/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
pub mod credential;
pub mod host_info;
pub mod parameter;
pub mod port;
pub mod result;
pub mod scan;
pub mod scan_action;
pub mod scanner_parameter;
pub mod status;
pub mod target;
pub mod vt;

#[cfg(test)]
mod tests {
use super::scan::Scan;

#[test]
fn parse_minimal() {
let json_str = r#"{
"target": {
"hosts": [
"127.0.0.1"
],
"ports": [
{
"range": "22"
}
]
},
"vts": [
{
"oid": "1.3.6.1.4.1.25623.1.0.10267"
}
]
}
"#;
// tests that it doesn't panic when parsing the json
let _: Scan = serde_json::from_str(json_str).unwrap();
}

#[test]
fn parses_complex_example() {
let json_str = r#"{
"scan_id": "6c591f83-8f7b-452a-8c78-ba35779e682f",
"target": {
"hosts": [
"127.0.0.1",
"192.168.0.1-15",
"10.0.5.0/24",
"::1",
"2001:db8:0000:0000:0000:0000:0000:0001-00ff",
"2002::1234:abcd:ffff:c0a8:101/64",
"examplehost"
],
"ports": [
{
"protocol": "udp",
"range": "22,1024-1030"
},
{
"protocol": "tcp",
"range": "24-30"
},
{
"range": "100-1000"
}
],
"credentials": [
{
"service": "ssh",
"port": 22,
"usk": {
"username": "user",
"password": "pw",
"private": "ssh-key..."
}
},
{
"service": "smb",
"up": {
"username": "user",
"password": "pw"
}
},
{
"service": "snmp",
"snmp": {
"username": "user",
"password": "pw",
"community": "my_community",
"auth_algorithm": "md5",
"privacy_password": "priv_pw",
"privacy_algorithm": "aes"
}
}
],
"alive_test_ports": [
{
"protocol": "tcp",
"range": "1-100"
},
{
"range": "443"
}
],
"alive_test_methods": [
"icmp",
"tcp_syn",
"tcp_ack",
"arp",
"consider_alive"
],
"reverse_lookup_unify": true,
"reverse_lookup_only": false
},
"scanner_parameters": [
{
"id": "target_port",
"value": "443"
},
{
"id": "use_https",
"value": "1"
},
{
"id": "profile",
"value": "fast_scan"
}
],
"vts": [
{
"oid": "1.3.6.1.4.1.25623.1.0.10662",
"parameters": [
{
"id": 1,
"value": "200"
},
{
"id": 2,
"value": "yes"
}
]
},
{
"oid": "1.3.6.1.4.1.25623.1.0.10330"
}
]
}
"#;
// tests that it doesn't panic when parsing the json
let _: Scan = serde_json::from_str(json_str).unwrap();
}
}
10 changes: 10 additions & 0 deletions rust/models/src/json/parameter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, Clone)]
/// Represents a parameter for a VTS configuration.
pub struct Parameter {
/// The ID of the parameter.
pub id: u16,
/// The value of the parameter.
pub value: String,
}
21 changes: 21 additions & 0 deletions rust/models/src/json/port.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use serde::{Deserialize, Serialize};

/// Represents a port representation for scanning.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Port {
#[serde(skip_serializing_if = "Option::is_none")]
/// Protocol for the given port range. If empty, prot range applies to UDP and TCP
protocol: Option<Protocol>,
/// Range for ports to scan. A range is defined by
/// range => <number>[-<number>][,<range>]
range: String,
}

/// Enum representing the protocol used for scanning a port.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Protocol {
#[serde(rename = "udp")]
UDP,
#[serde(rename = "tcp")]
TCP,
}
51 changes: 51 additions & 0 deletions rust/models/src/json/result.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use serde::{Deserialize, Serialize};

use super::port::Protocol;

/// Scan result
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Result {
/// Incremental ID of a result
pub id: usize,
#[serde(rename = "type")]
/// Type of the result
pub r_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
/// IP address
pub ip_address: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
/// DNS
pub hostname: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
/// ID of the VT, which generated the result
pub oid: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
/// Port
pub port: Option<i16>,
#[serde(skip_serializing_if = "Option::is_none")]
/// Protocol the port corresponds to
pub protocol: Option<Protocol>,
#[serde(skip_serializing_if = "Option::is_none")]
/// Additional information
pub message: Option<String>,
}

/// Enum of possible types of results
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum ResultType {
#[serde(rename = "alarm")]
/// Vulnerability
Alarm,
#[serde(rename = "log")]
/// Log message
Log,
#[serde(rename = "error")]
/// Some error occurred during a scan
Error,
#[serde(rename = "host_start")]
/// Information about the scan start of a host
HostStart,
#[serde(rename = "host_stop")]
/// Information about the scan end of a host
HostEnd,
}
18 changes: 18 additions & 0 deletions rust/models/src/json/scan.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use serde::{Deserialize, Serialize};

use super::{scanner_parameter::ScannerParameter, target::Target, vt::VT};

/// Struct for creating and getting a scan
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Scan {
#[serde(skip_serializing_if = "Option::is_none")]
/// Unique ID of a scan
pub scan_id: Option<String>,
/// Information about the target to scan
pub target: Target,
#[serde(skip_serializing_if = "Option::is_none")]
/// Configuration options for the scanner
pub scanner_parameters: Option<Vec<ScannerParameter>>,
/// List of VTs to execute for the target
pub vts: Vec<VT>,
}
18 changes: 18 additions & 0 deletions rust/models/src/json/scan_action.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use serde::{Deserialize, Serialize};

/// Action to perform on a scan
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ScanAction {
pub action: Action,
}

/// Enum representing possible actions
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Action {
#[serde(rename = "start")]
/// Start a scan
Start,
#[serde(rename = "stop")]
/// Stop a scan
Stop,
}
10 changes: 10 additions & 0 deletions rust/models/src/json/scanner_parameter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use serde::{Deserialize, Serialize};

/// Configuration parameter for the scanner
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ScannerParameter {
/// The ID of the parameter.
pub id: String,
/// The value of the parameter.
pub value: String,
}

0 comments on commit 8eb9234

Please sign in to comment.