1extern crate anyhow;
2extern crate chrono;
3#[macro_use]
4extern crate derive_is_enum_variant;
5extern crate serde;
6#[macro_use]
7extern crate serde_derive;
8extern crate serde_xml_rs;
9extern crate uuid;
10
11use std::collections::HashMap;
12use std::convert::TryFrom;
13
14use anyhow::{anyhow, Result};
15use chrono::prelude::*;
16use failure::_core::ops::Deref;
17use serde::{Deserialize, Deserializer};
18use serde::de::Error as SerdeError;
19
20macro_rules! get_or_err {
21 ($map:ident, $field_name:expr) => {
22
23 match $map.remove($field_name) {
24 Some(field) => field,
25 None => return Err(anyhow!("No field: {}", $field_name))
26 }
27
28 };
29
30 ($map:ident, $field_name:expr, $maperr:expr) => {
31
32 match $map.remove($field_name) {
33 Some(field) => field,
34 None => return Err(anyhow!("No field: {}", $field_name)).map_err($maperr)
35 }
36
37 };
38}
39
40#[derive(Debug, Clone, Hash)]
41#[derive(is_enum_variant)]
42pub enum Event {
43 ProcessCreate(ProcessCreateEvent),
44 FileCreate(FileCreateEvent),
45 InboundNetwork(NetworkEvent),
46 OutboundNetwork(NetworkEvent),
47}
48
49impl Event {
50 pub fn from_str(s: impl AsRef<str>) -> Result<Self> {
51 let s = s.as_ref();
52 serde_xml_rs::from_str::<ProcessCreateEvent>(s)
53 .map(|p| Event::ProcessCreate(p))
54 .or_else(|_|
55 serde_xml_rs::from_str::<FileCreateEvent>(s)
56 .map(|f| Event::FileCreate(f))
57 )
58 .or_else(|_|
59 serde_xml_rs::from_str::<NetworkEvent>(s)
60 .map(|n| {
61 if n.event_data.initiated {
62 Event::OutboundNetwork(n)
63
64 } else {
65 Event::InboundNetwork(n)
66 }
67 })
68 )
69 .map_err(|e| anyhow!("Error : {:?} {}", e, s))
70 }
71}
72
73
74#[derive(Debug, Deserialize, Clone, Hash)]
75pub struct Provider {
76 #[serde(rename = "Name")]
77 pub provider_name: String,
78 #[serde(rename = "Guid")]
79 pub provider_guid: String,
80}
81
82
83#[derive(Debug, Deserialize, Clone, Hash)]
84pub struct EventId {
85 #[serde(rename = "$value")]
86 pub event_id: u8,
87}
88
89#[derive(Debug, Deserialize, Clone, Hash)]
90pub struct Level {
91 #[serde(rename = "$value")]
92 pub level: String,
93}
94
95
96#[derive(Debug, Deserialize, Clone, Hash)]
97pub struct Task {
98 #[serde(rename = "$value")]
99 pub task: String,
100}
101
102
103#[derive(Debug, Deserialize, Clone, Hash)]
104pub struct Version {
105 #[serde(rename = "$value")]
106 pub version: String,
107}
108
109
110#[derive(Debug, Deserialize, Clone, Hash)]
111pub struct Opcode {
112 #[serde(rename = "$value")]
113 pub opcode: String,
114}
115
116#[derive(Debug, Deserialize, Clone, Hash)]
117pub struct Keywords {
118 #[serde(rename = "$value")]
119 pub keywords: String,
120}
121
122#[derive(Debug, Deserialize, Clone, Hash)]
123pub struct TimeCreated {
124 #[serde(rename = "SystemTime")]
125 pub system_time: String,
126}
127
128#[derive(Debug, Deserialize, Clone, Hash)]
129pub struct EventRecordId {
130 #[serde(rename = "$value")]
131 pub event_record_id: u32,
132}
133
134#[derive(Debug, Deserialize, Clone, Hash)]
135pub struct Execution {
136 #[serde(rename = "ProcessID")]
137 pub process_id: String,
138 #[serde(rename = "ThreadID")]
139 pub thread_id: String,
140}
141
142#[derive(Debug, Deserialize, Clone, Hash)]
143pub struct Channel {
144 #[serde(rename = "$value")]
145 pub value: String,
146}
147
148#[derive(Debug, Deserialize, Clone, Hash)]
149pub struct Computer {
150 #[serde(rename = "$value")]
151 pub computer: String,
152}
153
154#[derive(Debug, Deserialize, Clone, Hash)]
155pub struct Security {
156 #[serde(rename = "UserID")]
157 pub security: String,
158}
159
160#[derive(Debug, Deserialize, Clone, Hash)]
161pub struct System {
162 #[serde(rename = "Provider")]
164 pub provider: Provider,
165 #[serde(rename = "EventID")]
167 pub event_id: EventId,
168 #[serde(rename = "Version")]
170 pub version: Version,
171 #[serde(rename = "Level")]
173 pub level: Level,
174 #[serde(rename = "Task")]
176 pub task: Task,
177 #[serde(rename = "Opcode")]
179 pub opcode: Opcode,
180 #[serde(rename = "Keywords")]
182 pub keywords: Keywords,
183 #[serde(rename = "TimeCreated")]
185 pub time_created: TimeCreated,
186 #[serde(rename = "EventRecordID")]
188 pub event_record_id: EventRecordId,
189 #[serde(rename = "Execution")]
192 pub execution: Execution,
193 #[serde(rename = "Channel")]
195 pub channel: Channel,
196 #[serde(rename = "Computer")]
198 pub computer: Computer,
199 #[serde(rename = "Security")]
201 pub security: Security,
202}
203
204#[derive(Debug, Deserialize, Clone, Hash)]
205pub struct UtcTime {
206 #[serde(rename = "$value")]
207 pub utc_time: String
208}
209
210impl Deref for UtcTime {
211 type Target = str;
212
213 fn deref(&self) -> &str {
214 &self.utc_time
215 }
216}
217
218
219#[derive(Debug, Deserialize, Clone, Hash)]
220pub struct ProcessGuid {
221 pub process_guid: uuid::Uuid,
222}
223
224impl ProcessGuid {
225 pub fn get_creation_timestamp(&self) -> u64 {
226 let guid = self.process_guid.as_bytes();
227
228 const OFF: usize = 4;
229
230 let b = [guid[OFF + 1], guid[OFF], guid[OFF + 3], guid[OFF + 2]];
232
233 let ts = i32::from_le_bytes(b);
234 Utc.timestamp(ts as i64, 0).timestamp() as u64
235
236 }
237}
238
239#[derive(Debug, Deserialize, Clone, Hash)]
240pub struct Image {
241 pub image: String,
242}
243
244impl Deref for Image {
245 type Target = str;
246
247 fn deref(&self) -> &str {
248 &self.image
249 }
250}
251
252#[derive(Debug, Deserialize, Clone, Hash)]
253pub struct CommandLine {
254 pub command_line: String,
255}
256
257impl Deref for CommandLine {
258 type Target = str;
259
260 fn deref(&self) -> &str {
261 &self.command_line
262 }
263}
264
265#[derive(Debug, Deserialize, Clone, Hash)]
266pub struct CurrentDirectory {
267 pub current_directory: String,
268}
269
270impl Deref for CurrentDirectory {
271 type Target = str;
272
273 fn deref(&self) -> &str {
274 &self.current_directory
275 }
276}
277
278#[derive(Debug, Deserialize, Clone, Hash)]
279pub struct User {
280 pub user: String,
281}
282
283impl Deref for User {
284 type Target = str;
285
286 fn deref(&self) -> &str {
287 &self.user
288 }
289}
290
291#[derive(Debug, Deserialize, Clone, Hash)]
292pub struct LogonGuid {
293 pub logon_guid: uuid::Uuid,
294}
295
296impl Deref for LogonGuid {
297 type Target = uuid::Uuid;
298
299 fn deref(&self) -> &Self::Target {
300 &self.logon_guid
301 }
302}
303
304#[derive(Debug, Deserialize, Clone, Hash)]
305pub struct LogonId {
306 pub logon_id: String,
307}
308
309impl Deref for LogonId {
310 type Target = str;
311
312 fn deref(&self) -> &str {
313 &self.logon_id
314 }
315}
316
317#[derive(Debug, Deserialize, Clone, Hash)]
318pub struct TerminalSessionId {
319 pub terminal_session_id: String,
320}
321
322impl Deref for TerminalSessionId {
323 type Target = str;
324
325 fn deref(&self) -> &str {
326 &self.terminal_session_id
327 }
328}
329
330#[derive(Debug, Deserialize, Clone, Hash)]
331pub struct IntegrityLevel {
332 pub integrity_level: String,
333}
334
335impl Deref for IntegrityLevel {
336 type Target = str;
337
338 fn deref(&self) -> &str {
339 &self.integrity_level
340 }
341}
342
343#[derive(Debug, Deserialize, Clone, Hash)]
344pub struct Hashes {
345 pub hashes: String,
346}
347
348impl Deref for Hashes {
349 type Target = str;
350
351 fn deref(&self) -> &str {
352 &self.hashes
353 }
354}
355
356
357#[derive(Debug, Deserialize, Clone, Hash)]
358pub struct TargetFilename {
359 pub target_filename: String,
360}
361
362impl Deref for TargetFilename {
363 type Target = str;
364
365 fn deref(&self) -> &str {
366 &self.target_filename
367 }
368}
369
370
371#[derive(Debug, Deserialize, Clone, Hash)]
372pub struct ProcessCreateEventData {
373 pub utc_time: UtcTime,
375 pub process_guid: ProcessGuid,
377 pub process_id: u64,
379 pub image: Image,
381 pub command_line: CommandLine,
383 pub current_directory: CurrentDirectory,
385 pub user: User,
387 pub logon_guid: LogonGuid,
389 pub logon_id: LogonId,
391 pub terminal_session_id: TerminalSessionId,
393 pub integrity_level: IntegrityLevel,
395 pub hashes: Hashes,
397 pub parent_process_guid: ProcessGuid,
399 pub parent_process_id: u64,
401 pub parent_image: Image,
403 pub parent_command_line: CommandLine,
405}
406
407#[derive(Debug, Deserialize, Clone, Hash)]
408pub struct ProcessCreateEvent {
409 #[serde(rename = "System")]
410 pub system: System,
411 #[serde(rename = "EventData", deserialize_with="from_intermediary_data")]
412 pub event_data: ProcessCreateEventData,
413}
414
415
416
417
418#[derive(Debug, Deserialize, Clone, Hash)]
419pub struct FileCreateEventData {
420 pub utc_time: UtcTime,
421 pub process_guid: ProcessGuid,
422 pub process_id: u64,
423 pub image: Image,
424 pub target_filename: String,
425 pub creation_utc_time: UtcTime,
426}
427
428#[derive(Debug, Deserialize, Clone, Hash)]
429pub struct FileCreateEvent {
430 #[serde(rename = "System")]
431 pub system: System,
432
433 #[serde(rename = "EventData", deserialize_with="from_intermediary_data")]
434 pub event_data: FileCreateEventData
435}
436
437
438#[derive(Debug, Deserialize, Clone, Hash)]
439pub struct NetworkEventData {
440 pub utc_time: UtcTime,
441 pub process_guid: ProcessGuid,
442 pub process_id: u64,
443 pub image: Image,
444 pub user: Option<User>,
445 pub protocol: String,
446 pub initiated: bool,
447 pub source_is_ipv6: String,
448 pub source_ip: String,
449 pub source_hostname: Option<String>,
450 pub source_port: u16,
451 pub source_port_name: Option<String>,
452 pub destination_is_ipv6: String,
453 pub destination_ip: String,
454 pub destination_hostname: Option<String>,
455 pub destination_port: u16,
456 pub destination_port_name: Option<String>,
457}
458
459#[derive(Debug, Deserialize, Clone, Hash)]
460pub struct NetworkEvent {
461 #[serde(rename = "System")]
462 pub system: System,
463 #[serde(rename = "EventData", deserialize_with="from_intermediary_data")]
464 pub event_data: NetworkEventData,
465}
466
467impl TryFrom<IntermediaryEventData> for ProcessCreateEventData {
468 type Error = anyhow::Error;
469
470 fn try_from(inter: IntermediaryEventData) -> Result<Self> {
471 let mut m = HashMap::with_capacity(inter.data.len());
472
473 for data in inter.data {
474 if let Some(value) = data.value {
475m.insert(data.name, value);
479 }
480 }
481
482 let process_id = get_or_err!(m, "ProcessId");
483 let process_id: u64 = process_id.parse()?;
484
485 let parent_process_id = get_or_err!(m, "ParentProcessId");
486 let parent_process_id: u64 = parent_process_id.parse()?;
487
488
489 Ok(
490 ProcessCreateEventData {
491 utc_time: UtcTime {utc_time: get_or_err!(m, "UtcTime") },
492 process_guid: ProcessGuid {
493 process_guid: uuid::Uuid::parse_str(&get_or_err!(m, "ProcessGuid")[1..37])?
494 },
495 process_id,
496 image: Image { image: get_or_err!(m, "Image") },
497 command_line: CommandLine { command_line: get_or_err!(m, "CommandLine") },
498 current_directory: CurrentDirectory { current_directory: get_or_err!(m, "CurrentDirectory") },
499 user: User { user: get_or_err!(m, "User") },
500 logon_guid: LogonGuid {
501 logon_guid: uuid::Uuid::parse_str(&get_or_err!(m, "LogonGuid")[1..37])?
502 },
503 logon_id: LogonId { logon_id: get_or_err!(m, "LogonId") },
504 terminal_session_id: TerminalSessionId { terminal_session_id: get_or_err!(m, "TerminalSessionId") },
505 integrity_level: IntegrityLevel { integrity_level: get_or_err!(m, "IntegrityLevel") },
506 hashes: Hashes { hashes: get_or_err!(m, "Hashes") },
507 parent_process_guid: ProcessGuid {
508 process_guid: uuid::Uuid::parse_str(&get_or_err!(m, "ParentProcessGuid")[1..37])?
509 },
510 parent_process_id,
511 parent_image: Image { image: get_or_err!(m, "ParentImage") },
512 parent_command_line: CommandLine { command_line: get_or_err!(m, "ParentCommandLine") },
513 }
514 )
515 }
516}
517
518impl TryFrom<IntermediaryEventData> for FileCreateEventData {
519 type Error = anyhow::Error;
520
521 fn try_from(inter: IntermediaryEventData) -> Result<Self> {
522 let mut m = HashMap::with_capacity(inter.data.len());
523
524 for data in inter.data {
525 if let Some(value) = data.value {
526 m.insert(data.name, value);
527 }
528 }
529
530 let process_id = get_or_err!(m, "ProcessId");
531 let process_id = process_id.parse()?;
532
533 Ok(
534 FileCreateEventData {
535 utc_time: UtcTime { utc_time: get_or_err!(m, "UtcTime") },
536 process_guid: ProcessGuid {
537 process_guid: uuid::Uuid::parse_str(&get_or_err!(m, "ProcessGuid")[1..37])?
538 },
539 process_id,
540 image: Image { image: get_or_err!(m, "Image") },
541 creation_utc_time: UtcTime { utc_time: get_or_err!(m, "CreationUtcTime") },
542 target_filename: get_or_err!(m, "TargetFilename"),
543 }
544 )
545 }
546}
547
548impl TryFrom<IntermediaryEventData> for NetworkEventData {
549 type Error = anyhow::Error;
550
551 fn try_from(inter: IntermediaryEventData) -> Result<Self> {
552 let mut m = HashMap::with_capacity(inter.data.len());
553
554 for data in inter.data {
555 if let Some(value) = data.value {
556 m.insert(data.name, value);
557 }
558 }
559
560 let user = m.remove("User")
561 .map(|user| User { user });
562
563 Ok(
564 NetworkEventData {
565 utc_time: UtcTime {utc_time: get_or_err!(m, "UtcTime")},
566 process_guid: ProcessGuid {
567 process_guid: uuid::Uuid::parse_str(&get_or_err!(m, "ProcessGuid")[1..37])?
568 },
569 process_id: get_or_err!(m, "ProcessId").parse()?,
570 image: Image { image: get_or_err!(m, "Image") },
571 user,
572 protocol: get_or_err!(m, "Protocol"),
573 source_is_ipv6: get_or_err!(m, "SourceIsIpv6"),
574 source_ip: get_or_err!(m, "SourceIp"),
575 source_hostname: m.remove("SourceHostname"),
576 source_port_name: m.remove("SourcePortName"),
577 destination_is_ipv6: get_or_err!(m, "DestinationIsIpv6"),
578 destination_ip: get_or_err!(m, "DestinationIp"),
579 destination_hostname: m.remove("DestinationHostname"),
580 destination_port_name: m.remove("DestinationPortName"),
581 initiated: get_or_err!(m, "Initiated").parse()?,
582 source_port: get_or_err!(m, "SourcePort").parse()?,
583 destination_port: get_or_err!(m, "DestinationPort").parse()?,
584 }
585 )
586 }
587}
588
589fn from_intermediary_data<'de, D, T>(deserializer: D) -> Result<T, D::Error>
590 where
591 D: Deserializer<'de>,
592 T: TryFrom<IntermediaryEventData>,
593{
594 let s: IntermediaryEventData = Deserialize::deserialize(deserializer)?;
595 T::try_from(s).map_err(|_| SerdeError::custom("Failed to deserialize") )
596}
597
598#[derive(Debug, Deserialize, Clone, Hash)]
599pub struct Data {
600 #[serde(rename = "Name")]
601 pub name: String,
602 #[serde(rename = "$value")]
603 pub value: Option<String>,
604
605}
606
607
608#[derive(Debug, Deserialize, Clone, Hash)]
609pub struct IntermediaryEventData {
610 #[serde(rename = "Data")]
611 pub data: Vec<Data>
612}
613
614
615#[cfg(test)]
616mod tests {
617 use super::*;
618 use std::fs::File;
619 use std::io::{BufReader, BufRead};
620
621 const NETWORK_EVENT: &str = r#"
622 <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
623 <System>
624 <Provider Name="Microsoft-Windows-Sysmon" Guid="{5770385F-C22A-43E0-BF4C-06F5698FFBD9}" />
625 <EventID>3</EventID>
626 <Version>5</Version>
627 <Level>4</Level>
628 <Task>3</Task>
629 <Opcode>0</Opcode>
630 <Keywords>0x8000000000000000</Keywords>
631 <TimeCreated SystemTime="2017-04-28T22:12:23.657698300Z" />
632 <EventRecordID>10953</EventRecordID>
633 <Correlation />
634 <Execution ProcessID="3216" ThreadID="3976" />
635 <Channel>Microsoft-Windows-Sysmon/Operational</Channel>
636 <Computer>rfsH.lab.local</Computer>
637 <Security UserID="S-1-5-18" />
638 </System>
639 <EventData>
640 <Data Name="UtcTime">2017-04-28 22:12:22.557</Data>
641 <Data Name="ProcessGuid">{A23EAE89-BD28-5903-0000-00102F345D00}</Data>
642 <Data Name="ProcessId">13220</Data>
643 <Data Name="Image">C:\Program Files (x86)\Google\Chrome\Application\chrome.exe</Data>
644 <Data Name="User">LAB\rsmith</Data>
645 <Data Name="Protocol">tcp</Data>
646 <Data Name="Initiated">true</Data>
647 <Data Name="SourceIsIpv6">false</Data>
648 <Data Name="SourceIp">192.168.1.250</Data>
649 <Data Name="SourceHostname">rfsH.lab.local</Data>
650 <Data Name="SourcePort">3328</Data>
651 <Data Name="SourcePortName"></Data>
652 <Data Name="DestinationIsIpv6">false</Data>
653 <Data Name="DestinationIp">104.130.229.150</Data>
654 <Data Name="DestinationHostname"></Data>
655 <Data Name="DestinationPort">443</Data>
656 <Data Name="DestinationPortName">https</Data>
657 </EventData>
658 </Event>
659 "#;
660
661 const FILE_CREATE: &str = r#"
662 <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
663 <System>
664 <Provider Name="Microsoft-Windows-Sysmon" Guid="{5770385F-C22A-43E0-BF4C-06F5698FFBD9}" />
665 <EventID>11</EventID>
666 <Version>2</Version>
667 <Level>4</Level>
668 <Task>11</Task>
669 <Opcode>0</Opcode>
670 <Keywords>0x8000000000000000</Keywords>
671 <TimeCreated SystemTime="2017-05-13T19:44:55.314125100Z" />
672 <EventRecordID>734181</EventRecordID>
673 <Correlation />
674 <Execution ProcessID="2848" ThreadID="3520" />
675 <Channel>Microsoft-Windows-Sysmon/Operational</Channel>
676 <Computer>rfsH.lab.local</Computer>
677 <Security UserID="S-1-5-18" />
678 </System>
679 <EventData>
680 <Data Name="UtcTime">2017-05-13 19:44:55.313</Data>
681 <Data Name="ProcessGuid">{A23EAE89-6237-5917-0000-0010300E6601}</Data>
682 <Data Name="ProcessId">19200</Data>
683 <Data Name="Image">C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorsvw.exe</Data>
684 <Data Name="TargetFilename">C:\Windows\assembly\NativeImages_v4.0.30319_64\Temp\4b00-0\AxImp.exe</Data>
685 <Data Name="CreationUtcTime">2017-05-13 19:44:55.313</Data>
686 </EventData>
687 </Event>
688 "#;
689
690 const PROCESS_CREATE: &str = r#"
691 <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
692 <System>
693 <Provider Name="Microsoft-Windows-Sysmon" Guid="{5770385F-C22A-43E0-BF4C-06F5698FFBD9}" />
694 <EventID>1</EventID>
695 <Version>5</Version>
696 <Level>4</Level>
697 <Task>1</Task>
698 <Opcode>0</Opcode>
699 <Keywords>0x8000000000000000</Keywords>
700 <TimeCreated SystemTime="2017-04-28T22:08:22.025812200Z" />
701 <EventRecordID>9947</EventRecordID>
702 <Correlation />
703 <Execution ProcessID="3216" ThreadID="3964" />
704 <Channel>Microsoft-Windows-Sysmon/Operational</Channel>
705 <Computer>rfsH.lab.local</Computer>
706 <Security UserID="S-1-5-18" />
707 </System>
708 <EventData>
709 <Data Name="UtcTime">2017-04-28 22:08:22.025</Data>
710 <Data Name="ProcessGuid">{A23EAE89-BD56-5903-0000-0010E9D95E00}</Data>
711 <Data Name="ProcessId">6228</Data>
712 <Data Name="Image">C:\Program Files (x86)\Google\Chrome\Application\chrome.exe</Data>
713 <Data Name="CommandLine">"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --type=utility --lang=en-US --no-sandbox --service-request-channel-token=F47498BBA884E523FA93E623C4569B94 --mojo-platform-channel-handle=3432 /prefetch:8</Data>
714 <Data Name="CurrentDirectory">C:\Program Files (x86)\Google\Chrome\Application\58.0.3029.81\</Data>
715 <Data Name="User">LAB\rsmith</Data>
716 <Data Name="LogonGuid">{A23EAE89-B357-5903-0000-002005EB0700}</Data>
717 <Data Name="LogonId">0x7eb05</Data>
718 <Data Name="TerminalSessionId">1</Data>
719 <Data Name="IntegrityLevel">Medium</Data>
720 <Data Name="Hashes">SHA256=6055A20CF7EC81843310AD37700FF67B2CF8CDE3DCE68D54BA42934177C10B57</Data>
721 <Data Name="ParentProcessGuid">{A23EAE89-BD28-5903-0000-00102F345D00}</Data>
722 <Data Name="ParentProcessId">13220</Data>
723 <Data Name="ParentImage">C:\Program Files (x86)\Google\Chrome\Application\chrome.exe</Data>
724 <Data Name="ParentCommandLine">"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" </Data>
725 </EventData>
726 </Event>
727 "#;
728
729 const HEADER: &'static str = r#"
730 <System>
731 <Provider Name="Microsoft-Windows-Sysmon" Guid="{5770385F-C22A-43E0-BF4C-06F5698FFBD9}" />
732 <EventID>1</EventID>
733 <Version>5</Version>
734 <Level>4</Level>
735 <Task>1</Task>
736 <Opcode>0</Opcode>
737 <Keywords>0x8000000000000000</Keywords>
738 <TimeCreated SystemTime="2017-04-28T22:08:22.025812200Z" />
739 <EventRecordID>9947</EventRecordID>
740 <Correlation />
741 <Execution ProcessID="3216" ThreadID="3964" />
742 <Channel>Microsoft-Windows-Sysmon/Operational</Channel>
743 <Computer>rfsH.lab.local</Computer>
744 <Security UserID="S-1-5-18" />
745 </System>
746 "#;
747
748 #[test]
749 fn system() {
750 serde_xml_rs::from_str::<System>(HEADER).unwrap();
751 }
752
753 #[test]
754 fn process_create_event() {
755 serde_xml_rs::from_str::<ProcessCreateEvent>(PROCESS_CREATE).unwrap();
756 }
757
758 #[test]
759 fn file_create_event() {
760 serde_xml_rs::from_str::<FileCreateEvent>(FILE_CREATE).unwrap();
761 }
762
763 #[test]
764 fn network_event() {
765 serde_xml_rs::from_str::<NetworkEvent>(NETWORK_EVENT).unwrap();
766 }
767
768 #[test]
769 fn event_type() {
770 assert!(Event::from_str(NETWORK_EVENT).unwrap().is_outbound_network());
771 assert!(Event::from_str(FILE_CREATE).unwrap().is_file_create());
772 assert!(Event::from_str(PROCESS_CREATE).unwrap().is_process_create());
773 }
774
775 #[test]
776 fn parse_all() -> Result<()> {
777 let reader = BufReader::new(File::open("./test_data/events6.xml")?);
778
779 for event in reader.lines() {
780 if let Ok(event) = event {
781 if event.contains("EventID>1<") || event.contains("EventID>3<") || event.contains("EventID>11<") {
782 let parsed: Result<Event, _> = Event::from_str(&event);
783 if let Err(e) = parsed {
784 Err(e)?;
785 }
786 }
787 }
788 }
789
790 Ok(())
791 }
792}
793
794