mirror of https://github.com/OISF/suricata
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 variantpull/6324/head
parent
dbea7d636f
commit
27d1ee98ce
@ -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…
Reference in New Issue