Skip to content
Closed
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
4 changes: 4 additions & 0 deletions src/argument.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ pub enum Commands {
#[clap(short='l', long)]
path_to_logs: Option<PathBuf>,

/// Change path to Unix Socket
#[clap(short='s', long)]
path_to_socket: Option<PathBuf>,

/// Change the time of Suricata preconfiguration run (in seconds)
#[clap(short='t', long="time")]
preconf_time: Option<u64>,
Expand Down
96 changes: 78 additions & 18 deletions src/suricata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ SPDX-License-Identifier: BSD-3-Clause
This file executes Suricata.
*/

const PIDFILE: &str = "/var/run/suricata.pid";

use std::process::{Child, Command};
use crate::yaml::{emergency_check_memcap, Suriconf};
use crate::{FLOW_WINDOW, MIN_RUN};
Expand All @@ -16,10 +18,11 @@ use std::time::Duration;
use crossbeam_channel::{bounded, select, tick, Receiver};
use std::process::Stdio;
use std::io::{BufRead, BufReader};
use std::thread;
use procfs::process::{all_processes, Process};
use std::{fs, thread};
use procfs::process::{Process};
use signal_hook::consts::SIGINT;
use signal_hook::iterator::Signals;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicBool, Ordering};

Expand All @@ -35,6 +38,14 @@ pub fn execute_suricata<'a>(suriconf: &Suriconf, logs: &mut CreatedLogs, options
let mut suricata_again = SuricataAgain::default();

let mut vec_of_sur_cmd: Vec<String> = vec![];
match delete_pid_file() {
Err(e) => {
panic!("{e}");
}
Ok(()) => {}
};

set_pid_file(&mut vec_of_sur_cmd);
get_capture_mode(suriconf, &mut vec_of_sur_cmd);

if cfg!(target_os = "windows") {
Expand Down Expand Up @@ -66,7 +77,7 @@ pub fn execute_suricata<'a>(suriconf: &Suriconf, logs: &mut CreatedLogs, options
let mut child = Command::new("sudo")
.arg("-n")
.args(args)
.stdout(Stdio::piped())
.stdout(Stdio::null())
.stderr(Stdio::piped())
.spawn()
.expect("Failed to execute process.");
Expand All @@ -81,6 +92,14 @@ pub fn execute_suricata<'a>(suriconf: &Suriconf, logs: &mut CreatedLogs, options
}
});

let suri_pid = match wait_on_suricata_start(&suriconf.socket) {
Ok(pid) => pid,
Err(e) => {
kill_suricata(&mut child);
panic!("{e}")
}
};

let timeout = Duration::from_secs(suriconf.preconf_time);
let start = std::time::Instant::now();
let ticks_thread1 = tick(Duration::from_millis(100));
Expand Down Expand Up @@ -140,7 +159,6 @@ pub fn execute_suricata<'a>(suriconf: &Suriconf, logs: &mut CreatedLogs, options

let ticks = tick(Duration::from_millis(100));
let emergency_ticks = tick(Duration::from_secs(FLOW_WINDOW));
let suri_pid = check_process_name_for_suricata_main().expect("Unable to get Suricata-Main.");

loop {
select! {
Expand Down Expand Up @@ -198,6 +216,26 @@ pub fn get_capture_mode(suriconf: &Suriconf, vec_of_sur_cmd: &mut Vec<String>) {
});
}

pub fn delete_pid_file() -> std::io::Result<()> {
let status = Command::new("sudo")
.arg("-n")
.arg("rm")
.arg("-f")
.arg(PIDFILE)
.status()?;

if status.success() {
Ok(())
} else {
Err(std::io::Error::other("Failed to delete Suricata PID file."))
}
}

pub fn set_pid_file(vec_of_sur_cmd: &mut Vec<String>) {
vec_of_sur_cmd.push("--pidfile".to_string());
vec_of_sur_cmd.push(PIDFILE.to_string());
}

pub fn get_cpu_usage(sys: &mut SystemVar) {
sys.sys.refresh_cpu_usage();

Expand Down Expand Up @@ -272,24 +310,46 @@ pub fn get_workers(sys: &mut SystemVar) -> u64 {
}
workers
}

fn check_process_name_for_suricata_main() -> Option<i32> {
for _ in 0..10 {
for prc in all_processes().expect("Unable to get all processes.") {
let process: Process;
match prc {
Ok(prc) => {process = prc}
Err(_) => {continue}
fn get_suricata_pid() -> Result<i32, String> {
for _ in 0..20 {
if let Ok(content) = fs::read_to_string(PIDFILE) {
if let Ok(pid) = content.trim().parse::<i32>() {
if Path::new(&format!("/proc/{}", pid)).exists() {
return Ok(pid);
}
}

if process.stat().expect("Unable to find stats about process.").comm == "Suricata-Main" {
return Some(process.pid);
}
thread::sleep(Duration::from_millis(1000));
}
Err("Suricata process not found.".into())
}
fn wait_on_suricata_start(socket: &PathBuf) -> Result<i32, String> {
match get_suricata_pid() {
Ok(pid) => {
let socket = socket.to_str().ok_or("Socket path is not valid UTF-8.")?;
for _ in 0..120 {
let output = Command::new("sudo")
.arg("-n")
.arg("suricatasc")
.arg("-c")
.arg("uptime")
.arg(socket)
.status()
.map_err(|e| format!("Unable to execute Suricata socket control tool: {e}"))?;

if output.success() {
return Ok(pid)
}
thread::sleep(Duration::from_millis(1000));
}
Err("Suricata could not start.".into())
}
Err(e) => {
Err(e)
}
thread::sleep(Duration::from_millis(100));
}
None
}

fn get_cores_with_threads(suri_pid: i32, sys: &mut SystemVar) {
let proc = Process::new(suri_pid).expect("Unable to create process.");
let tasks = proc.tasks().expect("Unable to get process tasks.");
Expand Down Expand Up @@ -356,4 +416,4 @@ pub fn check_min_suricata_runtime_for_modules(suriconf: &Suriconf) {
panic!("Unable to execute Suricata and have enough samples from preconfiguration, \
FlowThreads module needs at least 6 minutes.")
}
}
}
1 change: 1 addition & 0 deletions src/suriconf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ ethtool-bin: /usr/bin/ethtool
ifconfig-bin: /usr/sbin/ifconfig
ip-bin: /usr/sbin/ip
log-dir: /var/log/suricata/
socket: /var/run/suricata/suricata-command.socket
preconf-time: 360 # in seconds
# 360 is minimum for flow_threads module
analysis: static # static/dynamic
Expand Down
12 changes: 12 additions & 0 deletions src/yaml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,7 @@ pub struct Suriconf {
pub ifconfig_bin: PathBuf,
pub ip_bin: PathBuf,
pub log_dir: PathBuf,
pub socket: PathBuf,
pub preconf_time: u64,
pub analysis: Analysis,
pub mode: Mode,
Expand Down Expand Up @@ -844,6 +845,13 @@ impl Suriconf {
self.find_log_dir(suriconf_string).expect("Unable to parse path to logs.")
};

self.socket = if let Some(Commands::Suricata { path_to_socket: Some(p), .. }) = &args.cmd {
p.clone()
}
else {
self.find_socket(suriconf_string).expect("Unable to parse path to unix socket.")
};

self.preconf_time = if let Some( Commands::Suricata { preconf_time: Some(p), .. }) = &args.cmd {
p.clone()
}
Expand Down Expand Up @@ -952,6 +960,10 @@ impl Suriconf {
text.get("log-dir").and_then(|c| c.as_str()).map(|c| PathBuf::from(c))
}

pub fn find_socket(&self, text: &Value) -> Option<PathBuf> {
text.get("socket").and_then(|c| c.as_str()).map(|c| PathBuf::from(c))
}

pub fn find_preconf_time(&self, text: &Value) -> Option<u64> {
text.get("preconf-time").and_then(|t| t.as_u64())
}
Expand Down
Loading