Skip to content

Commit

Permalink
Merge pull request #10 from kunai-project/fix-dup-match-names
Browse files Browse the repository at this point in the history
fix #9 : duplicate match names bug
  • Loading branch information
qjerome authored Nov 13, 2024
2 parents 2ba49b4 + b5da0dc commit 7c1dc04
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 3 deletions.
2 changes: 2 additions & 0 deletions gene/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![deny(unused_imports)]

mod event;
pub use event::{Event, FieldGetter};

Expand Down
23 changes: 20 additions & 3 deletions gene/src/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ mod condition;
// used to parse path
pub(crate) mod matcher;

mod map;
pub use map::MatchHashMap;

pub const MAX_SEVERITY: u8 = 10;

pub(crate) fn bound_severity(sev: u8) -> u8 {
Expand Down Expand Up @@ -110,7 +113,7 @@ pub struct Rule {
#[serde(rename = "match-on")]
pub match_on: Option<MatchOn>,
/// matches
pub matches: Option<HashMap<String, String>>,
pub matches: Option<MatchHashMap<String, String>>,
/// rule triggering condition
pub condition: Option<String>,
/// severity given to the events matching the rule
Expand Down Expand Up @@ -231,13 +234,13 @@ impl Rule {

// initializing operands
if let Some(matches) = self.matches {
for (operand, m) in matches {
for (operand, m) in matches.iter() {
if !operand.starts_with('$') {
return Err(Error::Compile(format!(
"operand must start with $, try with ${operand}"
)));
}
c.matches.insert(operand, Match::from_str(&m)?);
c.matches.insert(operand.clone(), Match::from_str(m)?);
}
}

Expand Down Expand Up @@ -867,4 +870,18 @@ condition: none of $ip

assert_eq!(cr.match_event(&event), Ok(true));
}

#[test]
fn test_deserialization_error() {
let test = r#"
---
name: test
matches:
$ip: .ip == "8.8.4.4"
$ip: .ip ~= "^8\.8\."
condition: none of $ip
..."#;

assert!(serde_yaml::from_str::<Rule>(test).is_err());
}
}
65 changes: 65 additions & 0 deletions gene/src/rules/map.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
use serde::{de, Deserialize, Deserializer, Serialize};
use std::{
collections::HashMap,
fmt,
ops::{Deref, DerefMut},
};

#[derive(Debug, Clone, Serialize)]
pub struct MatchHashMap<K, V>(HashMap<K, V>);

impl<K, V> Deref for MatchHashMap<K, V> {
type Target = HashMap<K, V>;
fn deref(&self) -> &Self::Target {
&self.0
}
}

impl<K, V> DerefMut for MatchHashMap<K, V> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}

impl<'de, K, V> Deserialize<'de> for MatchHashMap<K, V>
where
K: Deserialize<'de> + Eq + std::hash::Hash + fmt::Debug,
V: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct MatchMapVisitor<K, V>(std::marker::PhantomData<(K, V)>);

impl<'de, K, V> de::Visitor<'de> for MatchMapVisitor<K, V>
where
K: Deserialize<'de> + Eq + std::hash::Hash + fmt::Debug,
V: Deserialize<'de>,
{
type Value = MatchHashMap<K, V>;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a map with unique keys")
}

fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: de::MapAccess<'de>,
{
let mut values = HashMap::new();

while let Some((key, value)) = map.next_entry()? {
if values.contains_key(&key) {
return Err(de::Error::custom(format!("duplicate key found: {:?}", key)));
}
values.insert(key, value);
}

Ok(MatchHashMap(values))
}
}

deserializer.deserialize_map(MatchMapVisitor(std::marker::PhantomData))
}
}

0 comments on commit 7c1dc04

Please sign in to comment.