]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
rust/derive: allow event name to be set as attribute
authorJason Ish <jason.ish@oisf.net>
Mon, 23 Jan 2023 17:21:09 +0000 (11:21 -0600)
committerVictor Julien <vjulien@oisf.net>
Thu, 26 Jan 2023 14:51:54 +0000 (15:51 +0100)
When deriving AppLayerEvent, allow the event name to be set with the
"name" attribute in cases where the transformed name is not suitable.

This allows us to use enum variant names like
"FtpEventRequestCommandTooLong" for direct use in C, but is also a
name that doesn't transform well to an event name in rules, where we
want to see "request_command_too_long".

rust/derive/src/applayerevent.rs
rust/derive/src/lib.rs

index 6bcb0550324a744a7960bd1f07a29315caa9bb12..29475fa2d51b596e3ddfbaeda76d0bc0f307612a 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2021 Open Information Security Foundation
+/* Copyright (C) 2021-2023 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
@@ -25,19 +25,23 @@ pub fn derive_app_layer_event(input: TokenStream) -> TokenStream {
     let name = input.ident;
 
     let mut fields = Vec::new();
-    let mut vals = Vec::new();
-    let mut cstrings = Vec::new();
-    let mut names = Vec::new();
+    let mut event_ids = Vec::new();
+    let mut event_cstrings = Vec::new();
+    let mut event_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);
+                let event_name = if let Some(xname) = parse_name(&v.attrs) {
+                    xname.value()
+                } else {
+                    transform_name(&v.ident.to_string())
+                };
+                let cname = format!("{}\0", event_name);
+                event_names.push(event_name);
+                event_cstrings.push(cname);
+                event_ids.push(i as i32);
             }
         }
         _ => panic!("AppLayerEvent can only be derived for enums"),
@@ -58,26 +62,26 @@ pub fn derive_app_layer_event(input: TokenStream) -> TokenStream {
         impl #crate_id::applayer::AppLayerEvent for #name {
             fn from_id(id: i32) -> Option<#name> {
                 match id {
-                    #( #vals => Some(#name::#fields) ,)*
+                    #( #event_ids => Some(#name::#fields) ,)*
                     _ => None,
                 }
             }
 
             fn as_i32(&self) -> i32 {
                 match *self {
-                    #( #name::#fields => #vals ,)*
+                    #( #name::#fields => #event_ids ,)*
                 }
             }
 
             fn to_cstring(&self) -> &str {
                 match *self {
-                    #( #name::#fields => #cstrings ,)*
+                    #( #name::#fields => #event_cstrings ,)*
                 }
             }
 
             fn from_string(s: &str) -> Option<#name> {
                 match s {
-                    #( #names => Some(#name::#fields) ,)*
+                    #( #event_names => Some(#name::#fields) ,)*
                     _ => None
                 }
             }
@@ -120,6 +124,29 @@ pub fn transform_name(in_name: &str) -> String {
     out
 }
 
+/// Parse the event name from the "name" attribute.
+///
+/// For example:
+/// ```ignore
+/// #[derive(AppLayerEvent)]
+/// pub enum FtpEvent {
+///    #[name("request_command_too_long")]
+///    FtpEventRequestCommandTooLong,
+///    #[name("response_command_too_long")]
+///    FtpEventResponseCommandTooLong,
+/// }
+/// ```
+fn parse_name(attrs: &[syn::Attribute]) -> Option<syn::LitStr> {
+    for attr in attrs {
+        if attr.path.is_ident("name") {
+            if let Ok(val) = attr.parse_args::<syn::LitStr>() {
+                return Some(val);
+            }
+        }
+    }
+    None
+}
+
 #[cfg(test)]
 mod test {
     use super::*;
index c7ffc931f598596d3ca03ce1d2a969163ef7fa7b..2b4419e221f1c0df90ae2ddd3ecabb30f70cf99c 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020 Open Information Security Foundation
+/* Copyright (C) 2020-2023 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
@@ -32,12 +32,14 @@ mod applayerframetype;
 ///     MalformedData,
 ///     NotRequest,
 ///     NotResponse,
+///     #[name("reserved_z_flag_set")]
 ///     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)]
+/// for proper conversion to the name used in rules (one_tow_three) or
+/// optionally add a name attribute.
+#[proc_macro_derive(AppLayerEvent, attributes(name))]
 pub fn derive_app_layer_event(input: TokenStream) -> TokenStream {
     applayerevent::derive_app_layer_event(input)
 }