You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The function get_suricata_pid is declared as fn get_suricata_pid() -> Result<i32, String> with no parameters, but its body references child (via child.try_wait()), which is undefined in this scope. This will not compile. The function needs a child: &mut Child parameter, and the call site in wait_on_suricata_start must pass child accordingly.
fnget_suricata_pid() -> Result<i32,String>{for _ in0..20{ifletOk(content) = fs::read_to_string(PIDFILE){ifletOk(pid) = content.trim().parse::<i32>(){ifletOk(comm) = fs::read_to_string(format!("/proc/{}/comm", pid)){if comm.trim() == "Suricata-Main"{returnOk(pid);}}}}ifletSome(status) = child.try_wait().expect("Unable to get Suricata status."){returnErr(format!("Suricata exited during startup with status: {status}."));}
thread::sleep(Duration::from_millis(1000));}Err("Suricata process not found.".into())}
In get_suricata_pid, the PID is read from the pidfile and verified against /proc/{pid}/comm of a process named Suricata-Main, but there is no verification that this PID belongs to the child process spawned by this tool. If another Suricata instance is running (or starts) on the same machine while the pidfile has not yet been written, this function can return the PID of an unrelated Suricata process. The subsequent monitoring and kill_suricata logic would then act on the wrong process. Comparing against the child's PID (after sudo exec, they should match) would make this robust.
fnget_suricata_pid() -> Result<i32,String>{for _ in0..20{ifletOk(content) = fs::read_to_string(PIDFILE){ifletOk(pid) = content.trim().parse::<i32>(){ifletOk(comm) = fs::read_to_string(format!("/proc/{}/comm", pid)){if comm.trim() == "Suricata-Main"{returnOk(pid);}}}}ifletSome(status) = child.try_wait().expect("Unable to get Suricata status."){returnErr(format!("Suricata exited during startup with status: {status}."));}
thread::sleep(Duration::from_millis(1000));}Err("Suricata process not found.".into())}
The new socket field is now required: existing configuration files without a socket key (and no -s CLI flag) will hit the .expect("Unable to parse path to unix socket.") and panic. Since Suricata has a well-known default socket path (/var/run/suricata/suricata-command.socket), falling back to that default instead of panicking would preserve backward compatibility for existing users.
self.socket = ifletSome(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.")};
In wait_on_suricata_start, if the suricatasc binary is missing from PATH, Command::output() returns an Err which is immediately propagated via ?, producing the error "Unable to execute Suricata socket control tool" and killing Suricata. This is distinct from Suricata not yet being ready. That is arguably correct behavior, but note that if suricatasc exists yet consistently fails (e.g., wrong socket path in config), the loop retries for the full 120 seconds before erroring; a shorter failure for a definitive command-level failure would speed up diagnostics.
fn wait_on_suricata_start(socket:&PathBuf,child:&mutChild) -> Result<i32,String>{matchget_suricata_pid(){Ok(pid) => {let socket = socket.to_str().ok_or("Socket path is not valid UTF-8.")?;for _ in0..120{let output = Command::new("sudo").arg("-n").arg("suricatasc").arg("-c").arg("uptime").arg(socket).output().map_err(|e| format!("Unable to execute Suricata socket control tool: {e}"))?;if output.status.success(){returnOk(pid)}ifletSome(status) = child.try_wait().expect("Unable to get Suricata status."){returnErr(format!("Suricata exited during startup with status: {status}."));}
thread::sleep(Duration::from_millis(1000));}Err("Suricata could not start.".into())}Err(e) => {Err(e)}}
get_suricata_pid references child, but it is not a parameter of the function, so this will not compile. Pass the child process handle as a parameter (child: &mut Child) and forward it from wait_on_suricata_start. This also allows the early-exit detection to work correctly.
-fn get_suricata_pid() -> Result<i32, String> {+fn get_suricata_pid(child: &mut Child) -> 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 let Ok(comm) = fs::read_to_string(format!("/proc/{}/comm", pid)) {
if comm.trim() == "Suricata-Main" {
- return Ok(pid);+ return Ok(pid);
}
}
}
}
if let Some(status) = child.try_wait().expect("Unable to get Suricata status.") {
return Err(format!("Suricata exited during startup with status: {status}."));
- }+ }+ ...+}+fn wait_on_suricata_start(socket: &PathBuf, child: &mut Child) -> Result<i32, String> {+ match get_suricata_pid(child) {+ ...+ }+}+
Suggestion importance[1-10]: 9
__
Why: get_suricata_pid uses child.try_wait() without child being a parameter, which is a compile error in the new code. The suggestion correctly fixes this by passing the child handle through from wait_on_suricata_start, addressing a critical bug.
High
General
Validate socket tool response content
suricatasc can exit with status 0 even when the socket command fails (e.g., returning an error message in its output). Verify the command's textual response in addition to the exit status, for example by checking that the output does not contain an error indicator, to avoid treating a failed startup as successful.
- if output.status.success() {- return Ok(pid)+ let stdout = String::from_utf8_lossy(&output.stdout);+ if output.status.success() && !stdout.contains("error") && !stdout.contains("failed") {+ return Ok(pid);
}
Suggestion importance[1-10]: 5
__
Why: It is plausible that suricatasc returns exit status 0 even when the socket command fails, so checking the output content adds robustness to startup detection. However, the string-matching heuristic ("error"/"failed") is a somewhat crude and non-rigorous validation.
Low
Propagate startup failure instead of panicking
Panicking here unwinds the process while the spawned stderr-reader thread and the shared kill flag may not be finalized cleanly. Instead of panic!, prefer returning an error (or propagating None) so the caller can shut down threads and the child process in an orderly fashion.
Why: Returning None instead of panicking after kill_suricata leverages the existing Option return type and allows cleaner shutdown. It is a reasonable error-handling improvement, though the panic does kill the child first, so the impact is moderate.
Low
Preserve Suricata stdout for diagnostics
Discarding Suricata's stdout with Stdio::null() loses all diagnostic output that Suricata writes to stdout, making startup failures hard to diagnose. Consider redirecting stdout to a log file (e.g., under logs) or keeping it piped with a dedicated reader thread, mirroring the existing stderr handling.
+ let stdout_log = std::fs::File::create(logs.log_dir.join("suricata_stdout.log"))+ .expect("Unable to create Suricata stdout log file.");
let mut child = Command::new("sudo")
.arg("-n")
.args(args)
- .stdout(Stdio::null())+ .stdout(Stdio::from(stdout_log))
.stderr(Stdio::piped())
.spawn()
.expect("Failed to execute process.");
Suggestion importance[1-10]: 4
__
Why: The observation that Stdio::null() discards diagnostic output is valid, though the PR intentionally removed the piped stdout. The proposed fix references logs.log_dir which may not exist on CreatedLogs, making the improved code somewhat speculative, but the general direction improves debuggability.
Low
Author self-review: I have reviewed the PR code suggestions, and addressed the relevant ones.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR Type
Bug fix, Enhancement
Description
Reliably detect Suricata startup via PID file and socket
Add
path_to_socketCLI option andsocketconfig fieldReplace process-name scan with PID file verification
Kill Suricata and panic when startup fails
Diagram Walkthrough
File Walkthrough
argument.rs
Add CLI option for Suricata socket pathsrc/argument.rs
path_to_socketCLI option (-s) for Suricata commandyaml.rs
Add socket path to Suriconf configurationsrc/yaml.rs
socket: PathBuffield toSuriconfstructfind_socket()suricata.rs
Wait for Suricata startup via PID file and socketsrc/suricata.rs
PIDFILEconstant and pass--pidfileto Suricata viaset_pid_file()delete_pid_file()check_process_name_for_suricata_main()withget_suricata_pid()reading the PID file and verifying
/proc//commwait_on_suricata_start()pollingsuricatasc -c uptimeon thesocket; kill Suricata and panic on failure
README.md
Document socket configuration optionREADME.md
socketconfiguration option in the config tablesuriconf.yaml
Add default socket path to config filesrc/suriconf.yaml
socketpath/var/run/suricata/suricata-command.socket