crowdstrike_cloudproto/services/ts/
event.rs

1use crate::framing::CloudProtoError;
2use byteorder::{ReadBytesExt, WriteBytesExt, BE};
3use std::io::{Read, Write};
4use strum_macros::{AsRefStr, Display, FromRepr};
5
6// Does not count the txid, which is handled transparently in the TsEventSocket
7pub(crate) const EVT_HDR_LEN: usize = 4;
8
9/// The `data` field usually contains a serialized Protobuf structure.
10///
11/// The Protobuf schema of the `data` depends entirely on `raw_event_id`,
12/// and this crate does not provide deserialization for specific events.
13///
14/// A few event IDs do not correspond to protobuf data at all, using a variety of other simple binary formats.
15///
16/// The `event_id` field is `None` for values of `raw_event_id` that are not in the [`EventId`](EventId) enum.
17#[derive(Eq, PartialEq, Debug, Clone)]
18pub struct Event {
19    pub raw_event_id: u32,
20    pub event_id: Option<EventId>,
21    pub data: Vec<u8>,
22}
23
24impl Event {
25    pub fn new(event_id: EventId, data: Vec<u8>) -> Self {
26        Self {
27            raw_event_id: event_id as u32,
28            event_id: Some(event_id),
29            data,
30        }
31    }
32
33    pub fn new_raw(raw_event_id: u32, data: Vec<u8>) -> Self {
34        Self {
35            raw_event_id,
36            event_id: None,
37            data,
38        }
39    }
40
41    /// Best effort text representation of the event ID using know [`EventId`][EventId] values
42    pub fn ev_id_string(&self) -> String {
43        if let Some(id) = self.event_id {
44            id.to_string()
45        } else {
46            format!("{:#X}", self.raw_event_id)
47        }
48    }
49
50    pub(crate) fn from_read(reader: &mut dyn Read) -> Result<Self, CloudProtoError> {
51        let raw_event_id = reader.read_u32::<BE>()?;
52        let event_id = EventId::from_repr(raw_event_id);
53        let mut data = Vec::new();
54        reader.read_to_end(&mut data)?;
55        Ok(Self {
56            raw_event_id,
57            event_id,
58            data,
59        })
60    }
61
62    pub(crate) fn into_write(self, writer: &mut dyn Write) -> Result<(), CloudProtoError> {
63        writer.write_u32::<BE>(self.raw_event_id)?;
64        writer.write_all(&self.data)?;
65        writer.flush()?;
66        Ok(())
67    }
68}
69
70/// Tries to provide meaningful names for some well-known [`Event`](Event)s.
71///
72/// Event ID names containing `UNK` are known to exist, but were not found in the form of an immediate value in falcon-sensor,
73/// so that some effort (beyond a simple lookup in the client) may be required to name them.
74///
75/// Some Event IDs are internal to falcon-sensor and never leave on the wire, so they are not listed.
76/// Some events have not been observed yet, or may be added in later updates,
77/// so this enum is only meant to document well-known values as a best-effort.
78/// It won't be an exhaustive list.
79#[derive(Eq, PartialEq, Debug, Copy, Clone, Display, AsRefStr, FromRepr)]
80#[repr(u32)]
81#[rustfmt::skip]
82#[allow(non_camel_case_types)]
83#[allow(dead_code)]
84#[non_exhaustive]
85pub enum EventId {
86    ConfigurationLoaded =           0x308000AA,
87    LfoDownloadFromManifestRecord = 0x308000AD,
88    ChannelDownloadComplete =       0x308001D2,
89    UNK_SERVER_0x30800207 =         0x30800207, // Sent by server, but no search results in sensor
90    CurrentSystemTags =             0x30800208,
91    CloudRequestReceived =          0x3080028E,
92    UNK_0x30800296 =                0x30800296, // No search results in sensor
93    IpAddressAddedForFamily2 =      0x308002e5, // I think this is IPv4, and the other IPv6?
94    IpAddressAdded =                0x308002e6,
95    HostnameChanged =               0x3080034D,
96    CurrentUninstallTokenInfo =     0x30800457,
97    ChannelRundown =                0x30800550,
98    ChannelDiffDownload =           0x3080064E,
99    DiskCapacity =                  0x3080069f,
100    DiskUtilization =               0x30800850,
101    UNK_0x31000002 =                0x31000002, // No search results in sensor
102    ChannelVersionRequired =        0x310001D1,
103    UNK_0x3100053f =                0x3100053f, // No search results in sensor
104    SystemCapacity =                0x310005AB,
105    UpdateCloudEvent =              0x318002B1,
106    OsVersionInfo =                 0x3200014e,
107    UNK_0x32000220 =                0x32000220, // No search results in sensor
108    UNK_0x320002cf =                0x320002cf, // No search results in sensor
109    ConnectionStatus =              0x32800139,
110    AgentOnline =                   0x338000ac,
111    UNK_0x340000ee =                0x340000ee, // No search results in sensor
112}
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117    use bytes::Buf;
118
119    #[test]
120    fn test_known_id_string() {
121        let ev = Event::new(EventId::AgentOnline, vec![]);
122        assert_eq!(ev.ev_id_string(), "AgentOnline")
123    }
124
125    #[test]
126    fn test_unknown_id_string() {
127        let ev = Event::new_raw(0xAABBCCDD, vec![]);
128        assert_eq!(ev.ev_id_string(), "0xAABBCCDD")
129    }
130
131    #[test]
132    fn test_event_serde_rountrip() {
133        let ev = Event::new_raw(0xAABBCCDD, vec![]);
134        let mut buf = Vec::new();
135        ev.clone().into_write(&mut buf).unwrap();
136        let ev2 = Event::from_read(&mut buf.reader()).unwrap();
137        assert_eq!(ev, ev2);
138    }
139}