rust: derive crate: for custom derives

Currently has one derive, AppLayerEvent to be used like:

  #[derive(AppLayerEvent)]
  pub enum DNSEvent {
      MalformedData,
      NotRequest,
      NotResponse,
      ZFlagSet,
  }

Code will be generated to:
- Convert enum to a c type string
- Convert string to enum variant
- Convert id to enum variant
pull/6324/head
Jason Ish 5 years ago committed by Victor Julien
parent dbea7d636f
commit 27d1ee98ce

@ -2694,7 +2694,7 @@ 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.toml rust/.cargo/config)
AC_CONFIG_FILES(Makefile src/Makefile rust/Makefile rust/Cargo.toml rust/derive/Cargo.toml rust/.cargo/config)
AC_CONFIG_FILES(qa/Makefile qa/coccinelle/Makefile)
AC_CONFIG_FILES(rules/Makefile doc/Makefile doc/userguide/Makefile doc/devguide/Makefile)
AC_CONFIG_FILES(contrib/Makefile contrib/file_processor/Makefile contrib/file_processor/Action/Makefile contrib/file_processor/Processor/Makefile)

2
rust/.gitignore vendored

@ -1,6 +1,6 @@
!Cargo.toml.in
Cargo.toml
/.cargo/config
/Cargo.toml
/Cargo.lock
/target
/vendor

@ -3,6 +3,9 @@ name = "suricata"
version = "@PACKAGE_VERSION@"
edition = "2018"
[workspace]
members = [".", "./derive"]
[lib]
crate-type = ["staticlib", "rlib"]
path = "@e_rustdir@/src/lib.rs"
@ -50,5 +53,7 @@ md-5 = "~0.9.1"
regex = "~1.4.2"
lazy_static = "~1.4.0"
suricata-derive = { path = "./derive" }
[dev-dependencies]
test-case = "~1.1.0"

@ -73,7 +73,7 @@ maintainerclean-local:
check:
CARGO_HOME="$(CARGO_HOME)" @rustup_home@ \
CARGO_TARGET_DIR="$(abs_top_builddir)/rust/target" \
$(CARGO) test $(RELEASE) --features "$(RUST_FEATURES)"
$(CARGO) test --all $(RELEASE) --features "$(RUST_FEATURES)"
if HAVE_CARGO_VENDOR
vendor:

@ -0,0 +1 @@
/target

@ -0,0 +1,13 @@
[package]
name = "suricata-derive"
version = "@PACKAGE_VERSION@"
edition = "2018"
[lib]
proc-macro = true
path = "@e_rustdir@/derive/src/lib.rs"
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = "1.0"

@ -0,0 +1,108 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{self, parse_macro_input, DeriveInput};
pub fn derive_app_layer_event(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
let mut fields = Vec::new();
let mut vals = Vec::new();
let mut cstrings = Vec::new();
let mut names = Vec::new();
match input.data {
syn::Data::Enum(ref data) => {
for (i, v) in (&data.variants).into_iter().enumerate() {
fields.push(v.ident.clone());
let name = transform_name(&v.ident.to_string());
let cname = format!("{}\0", name);
names.push(name);
cstrings.push(cname);
vals.push(i as i32);
}
}
_ => panic!("AppLayerEvent can only be derived for enums"),
}
let expanded = quote! {
impl crate::applayer::AppLayerEvent for #name {
fn from_id(id: i32) -> Option<#name> {
match id {
#( #vals => Some(#name::#fields) ,)*
_ => None,
}
}
fn as_i32(&self) -> i32 {
match *self {
#( #name::#fields => #vals ,)*
}
}
fn to_cstring(&self) -> &str {
match *self {
#( #name::#fields => #cstrings ,)*
}
}
fn from_string(s: &str) -> Option<#name> {
match s {
#( #names => Some(#name::#fields) ,)*
_ => None
}
}
}
};
proc_macro::TokenStream::from(expanded)
}
/// Transform names such as "OneTwoThree" to "one_two_three".
pub fn transform_name(in_name: &str) -> String {
let mut out = String::new();
for (i, c) in in_name.chars().enumerate() {
if i == 0 {
out.push_str(&c.to_lowercase().to_string());
} else if c.is_uppercase() {
out.push('_');
out.push_str(&c.to_lowercase().to_string());
} else {
out.push(c);
}
}
out
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_transform_name() {
assert_eq!(transform_name("One"), "one".to_string());
assert_eq!(transform_name("SomeEvent"), "some_event".to_string());
assert_eq!(
transform_name("UnassignedMsgType"),
"unassigned_msg_type".to_string()
);
}
}

@ -0,0 +1,42 @@
/* Copyright (C) 2020 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
extern crate proc_macro;
use proc_macro::TokenStream;
mod applayerevent;
/// The `AppLayerEvent` derive macro generates a `AppLayerEvent` trait
/// implementation for enums that define AppLayerEvents.
///
/// Example usage (DNS app-layer events):
///
/// #[derive(AppLayerEvent)]
/// enum {
/// MalformedData,
/// NotRequest,
/// NotResponse,
/// ZFlagSet,
/// }
///
/// The enum variants must follow the naming convention of OneTwoThree
/// for proper conversion to the name used in rules (one_tow_three).
#[proc_macro_derive(AppLayerEvent)]
pub fn derive_app_layer_event(input: TokenStream) -> TokenStream {
applayerevent::derive_app_layer_event(input)
}
Loading…
Cancel
Save