From 48920bd7843224c6a6ebb2cc9fb35323da200457 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Mon, 23 Jan 2023 11:21:09 -0600 Subject: [PATCH] rust/derive: allow event name to be set as attribute 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 | 53 ++++++++++++++++++++++++-------- rust/derive/src/lib.rs | 8 +++-- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/rust/derive/src/applayerevent.rs b/rust/derive/src/applayerevent.rs index 6bcb055032..29475fa2d5 100644 --- a/rust/derive/src/applayerevent.rs +++ b/rust/derive/src/applayerevent.rs @@ -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 { + for attr in attrs { + if attr.path.is_ident("name") { + if let Ok(val) = attr.parse_args::() { + return Some(val); + } + } + } + None +} + #[cfg(test)] mod test { use super::*; diff --git a/rust/derive/src/lib.rs b/rust/derive/src/lib.rs index c7ffc931f5..2b4419e221 100644 --- a/rust/derive/src/lib.rs +++ b/rust/derive/src/lib.rs @@ -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) }