Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[draft] Rewrite suricatasc in Rust - v0 #8571

Closed
wants to merge 3 commits into from
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
16 changes: 6 additions & 10 deletions .github/workflows/builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2566,7 +2566,7 @@ jobs:
windows-msys2-mingw64-libpcap:
name: Windows MSYS2 MINGW64 (libpcap)
runs-on: windows-latest
needs: [prepare-deps]
needs: [prepare-deps, almalinux-8]
defaults:
run:
shell: msys2 {0}
Expand All @@ -2576,27 +2576,23 @@ jobs:
with:
path: ~/.cargo
key: ${{ github.job }}-cargo
- uses: actions/checkout@v3.5.3
- uses: msys2/setup-msys2@v2
with:
msystem: MINGW64
update: true
install: git mingw-w64-x86_64-toolchain automake1.16 automake-wrapper autoconf libtool libyaml-devel pcre2-devel jansson-devel make mingw-w64-x86_64-libyaml mingw-w64-x86_64-pcre2 mingw-w64-x86_64-rust mingw-w64-x86_64-jansson unzip p7zip python-setuptools mingw-w64-x86_64-python-yaml mingw-w64-x86_64-jq mingw-w64-x86_64-libxml2 libpcap-devel mingw-w64-x86_64-libpcap
# hack: install our own cbindgen system wide as we can't get the
# preinstalled one to be picked up by configure
- name: cbindgen
run: cargo install --root /usr --force --debug --version 0.24.3 cbindgen
- uses: actions/checkout@v3.5.3
- uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a
with:
name: prep
path: prep
- run: tar xf prep/libhtp.tar.gz
- run: tar xf prep/suricata-update.tar.gz
- name: Download suricata.tar.gz
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a
with:
name: dist
- run: tar xvf suricata-*.tar.gz --strip-components=1
- run: tar xf prep/suricata-verify.tar.gz
- name: Build
run: |
./autogen.sh
CFLAGS="-ggdb -Werror" ./configure --enable-unittests --enable-gccprotect --disable-gccmarch-native --disable-shared --with-libpcap-includes=/npcap/Include --with-libpcap-libraries=/npcap/Lib/x64
make -j3
- name: Run
Expand Down
3 changes: 3 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -2590,6 +2590,9 @@ AC_SUBST(enable_non_bundled_htp)
AM_CONDITIONAL([BUILD_SHARED_LIBRARY], [test "x$enable_shared" = "xyes"] && [test "x$can_build_shared_library" = "xyes"])

AC_CONFIG_FILES(Makefile src/Makefile rust/Makefile rust/Cargo.lock rust/Cargo.toml rust/derive/Cargo.toml rust/.cargo/config)
AC_CONFIG_FILES(rust/client/Makefile rust/client/Cargo.toml)
AC_CONFIG_FILES(rust/suricatactl/Makefile rust/suricatactl/Cargo.toml)
AC_CONFIG_FILES(rust/suricatasc/Makefile rust/suricatasc/Cargo.toml)
AC_CONFIG_FILES(qa/Makefile qa/coccinelle/Makefile)
AC_CONFIG_FILES(rules/Makefile doc/Makefile doc/userguide/Makefile)
AC_CONFIG_FILES(contrib/Makefile contrib/file_processor/Makefile contrib/file_processor/Action/Makefile contrib/file_processor/Processor/Makefile)
Expand Down
12 changes: 0 additions & 12 deletions python/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@ LIBS = \
suricata/sc/suricatasc.py \
suricatasc/__init__.py

BINS = \
suricatasc \
suricatactl

EXTRA_DIST = $(LIBS) bin suricata/config/defaults.py

if HAVE_PYTHON
Expand All @@ -24,21 +20,13 @@ install-exec-local:
install -d -m 0755 "$(DESTDIR)$(prefix)/lib/suricata/python/suricata/ctl"
install -d -m 0755 "$(DESTDIR)$(prefix)/lib/suricata/python/suricata/sc"
install -d -m 0755 "$(DESTDIR)$(prefix)/lib/suricata/python/suricatasc"
install -d -m 0755 "$(DESTDIR)$(prefix)/bin"
for src in $(LIBS); do \
install -m 0644 $(srcdir)/$$src "$(DESTDIR)$(prefix)/lib/suricata/python/$$src"; \
done
install suricata/config/defaults.py \
"$(DESTDIR)$(prefix)/lib/suricata/python/suricata/config/defaults.py"
for bin in $(BINS); do \
cat "$(srcdir)/bin/$$bin" | \
sed -e "1 s,.*,#"'!'" ${HAVE_PYTHON}," > "${DESTDIR}$(bindir)/$$bin"; \
chmod 0755 "$(DESTDIR)$(bindir)/$$bin"; \
done

uninstall-local:
rm -f $(DESTDIR)$(bindir)/suricatactl
rm -f $(DESTDIR)$(bindir)/suricatasc
rm -rf $(DESTDIR)$(prefix)/lib/suricata/python

clean-local:
Expand Down
15 changes: 13 additions & 2 deletions rust/Cargo.toml.in
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,18 @@ version = "@PACKAGE_VERSION@"
edition = "2021"

[workspace]
members = [".", "./derive"]
members = [
".",
"derive",
"client",
"suricatactl",
"suricatasc",
]
default-members = [
".",
"suricatactl",
"suricatasc",
]

[lib]
crate-type = ["staticlib", "rlib"]
Expand All @@ -23,7 +34,7 @@ debug-validate = []

[dependencies]
nom7 = { version="7.0", package="nom" }
bitflags = "~1.2.1"
bitflags = "~1.3.2"
byteorder = "~1.4.2"
uuid = "~0.8.2"
crc = "~1.8.1"
Expand Down
20 changes: 17 additions & 3 deletions rust/Makefile.am
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
SUBDIRS = client \
suricatactl \
suricatasc

EXTRA_DIST = src derive \
.cargo/config.in \
cbindgen.toml \
dist/rust-bindings.h \
vendor
vendor \
client \
suricatactl \
suricatasc

if !DEBUG
RELEASE = --release
Expand Down Expand Up @@ -30,13 +37,13 @@ endif

all-local: Cargo.toml
if HAVE_CYGPATH
@rustup_home@ \
@rustup_home@ LOCALSTATEDIR=$(e_localstatedir) \
CARGO_HOME="$(CARGO_HOME)" \
CARGO_TARGET_DIR="$(e_rustdir)/target" \
$(CARGO) build $(RELEASE) \
--features "$(RUST_FEATURES)" $(RUST_TARGET)
else
@rustup_home@ \
@rustup_home@ LOCALSTATEDIR=$(e_localstatedir) \
CARGO_HOME="$(CARGO_HOME)" \
CARGO_TARGET_DIR="$(abs_top_builddir)/rust/target" \
$(CARGO) build $(RELEASE) $(NIGHTLY_ARGS) \
Expand All @@ -52,12 +59,19 @@ endif
fi
$(MAKE) gen/rust-bindings.h

install-exec-local:
install -d -m 0755 "$(DESTDIR)$(bindir)"
install -m 0755 $(RUST_SURICATA_LIBDIR)/suricatasc "$(DESTDIR)$(bindir)/suricatasc"
install -m 0755 $(RUST_SURICATA_LIBDIR)/suricatactl "$(DESTDIR)$(bindir)/suricatactl"

install-library:
$(MKDIR_P) "$(DESTDIR)$(libdir)"
$(INSTALL_DATA) $(RUST_SURICATA_LIB) "$(DESTDIR)$(libdir)"

uninstall-local:
rm -f "$(DESTDIR)$(libdir)/$(RUST_SURICATA_LIBNAME)"
rm -f "$(DESTDIR)$(bindir)/suricatasc"
rm -f "$(DESTDIR)$(bindir)/suricatactl"

clean-local:
rm -rf target
Expand Down
16 changes: 16 additions & 0 deletions rust/client/Cargo.toml.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "suricata-client"
version = "@PACKAGE_VERSION@"
edition = "2021"
license = "MIT"
description = "Suricata socket control client library"

[lib]
path = "@e_rustdir@/client/src/lib.rs"

[dependencies]
thiserror = { version = "1.0.38" }

# Serde pinned for Rust 1.63.0
serde = { version = "=1.0.152", default_features = false, features = ["derive"] }
serde_json = { version = "=1.0.93", default_features = false, features = ["preserve_order"] }
25 changes: 25 additions & 0 deletions rust/client/LICENSE-MIT
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Copyright (C) 2023 Open Information Security Foundation

Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
1 change: 1 addition & 0 deletions rust/client/Makefile.am
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
all-local: Cargo.toml
7 changes: 7 additions & 0 deletions rust/client/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# suricata-client

This is a Rust library that implements a client for the Suricata
control socket.

This is a blocking client with minimal dependencies to keep the size
of the vendored sources down.
24 changes: 24 additions & 0 deletions rust/client/examples/iface-list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-FileCopyrightText: Copyright 2023 Open Information Security Foundation
// SPDX-License-Identifier: MIT

/// This example connects to the Suricata control socket and requests
/// the interface list.
use serde_json::json;
use suricata_client::unix::Client;

fn main() -> Result<(), Box<dyn std::error::Error>> {
let args: Vec<String> = std::env::args().collect();

let filename = if let Some(filename) = args.get(1) {
filename
} else {
"/run/suricata/suricata-command.socket"
};
dbg!(filename);

let mut client = Client::connect(filename, false)?;
client.send(&json!({"command": "iface-list"}))?;
let response = client.read()?;
dbg!(response);
Ok(())
}
5 changes: 5 additions & 0 deletions rust/client/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2023 Open Information Security Foundation
// SPDX-License-Identifier: MIT

#[cfg(not(target_os = "windows"))]
pub mod unix;
87 changes: 87 additions & 0 deletions rust/client/src/unix.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// SPDX-FileCopyrightText: Copyright 2023 Open Information Security Foundation
// SPDX-License-Identifier: MIT

use serde::Deserialize;
use serde::Serialize;
use serde_json::json;
use std::io::{BufRead, BufReader, Write};
use std::os::unix::net::UnixStream;
use thiserror::Error;

#[derive(Debug, Error)]
pub enum ClientError {
#[error("ioerror: `{0}`")]
IoError(#[from] std::io::Error),
#[error("serde error: `{0}`")]
DeserializeError(#[from] serde_json::Error),
#[error("connection closed")]
Closed,
}

pub struct Client {
socket: UnixStream,

// If set, the client will print to stdout the messages sent and
// received. Primarily useful when running with the interactive
// client in verbose mode.
verbose: bool,
}

impl Client {
pub fn connect<T: AsRef<str>>(filename: T, verbose: bool) -> Result<Self, ClientError> {
let filename = filename.as_ref().to_string();
let socket = UnixStream::connect(filename)?;
let mut client = Self { socket, verbose };
client.handshake()?;
Ok(client)
}

fn handshake(&mut self) -> Result<(), ClientError> {
self.send(&json!({"version": "0.2"}))?;
self.read().map(serde_json::from_value::<Response>)??;
Ok(())
}

pub fn send<T>(&mut self, msg: &T) -> Result<(), std::io::Error>
where
T: ?Sized + Serialize,
{
let mut encoded = serde_json::to_string(&msg)?;
if self.verbose {
println!("SND: {}", &encoded);
}
encoded.push('\n');
self.socket.write_all(encoded.as_bytes())?;
Ok(())
}

/// Read a line of data from the client.
///
/// An empty line means the server has disconnected.
pub fn read_line(&self) -> Result<String, ClientError> {
let mut reader = BufReader::new(&self.socket);
let mut response = String::new();
reader.read_line(&mut response)?;
if self.verbose {
println!("RCV: {}", response.trim_end());
}
Ok(response)
}

pub fn read(&self) -> Result<serde_json::Value, ClientError> {
let line = self.read_line()?;
if line.is_empty() {
return Err(ClientError::Closed);
}
let decoded = serde_json::from_str(&line)?;
Ok(decoded)
}
}

#[derive(Debug, Deserialize)]
pub struct Response {
#[serde(rename = "return")]
pub status: String,
#[serde(default)]
pub message: serde_json::Value,
}
21 changes: 21 additions & 0 deletions rust/suricatactl/Cargo.toml.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "suricatactl"
version = "@PACKAGE_VERSION@"
edition = "2021"
license = "GPL-2.0-only"

[[bin]]
name = "suricatactl"
path = "@e_rustdir@/suricatactl/src/main.rs"

[dependencies]
regex = "~1.5.5"
tracing = "0.1"
tracing-subscriber = "0.3"

# 4.0 is the newest version that builds with Rust 1.63.0.
clap = { version = "~4.0.0", features = ["derive"] }

# This dependency is not used directly, but we have to pin this back
# to 0.3.0 for Rust 1.63.0.
clap_lex = "=0.3.0"
1 change: 1 addition & 0 deletions rust/suricatactl/Makefile.am
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
all-local: Cargo.toml
4 changes: 4 additions & 0 deletions rust/suricatactl/src/filestore/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2023 Open Information Security Foundation
// SPDX-License-Identifier: GPL-2.0-only

pub(crate) mod prune;
Loading
Loading