1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
use std::process;
use futures::{
future::{self, Either},
stream::{Stream, StreamExt, TryStream},
FutureExt,
};
use netlink_proto::{sys::SocketAddr, ConnectionHandle};
use crate::packet::{
rules::RuleMessage,
AuditMessage,
NetlinkMessage,
NetlinkPayload,
StatusMessage,
NLM_F_ACK,
NLM_F_CREATE,
NLM_F_DUMP,
NLM_F_EXCL,
NLM_F_NONREC,
NLM_F_REQUEST,
};
pub const AUDIT_STATUS_ENABLED: u32 = 1;
pub const AUDIT_STATUS_FAILURE: u32 = 2;
pub const AUDIT_STATUS_PID: u32 = 4;
pub const AUDIT_STATUS_RATE_LIMIT: u32 = 8;
pub const AUDIT_STATUS_BACKLOG_LIMIT: u32 = 16;
pub const AUDIT_STATUS_BACKLOG_WAIT_TIME: u32 = 32;
pub const AUDIT_STATUS_LOST: u32 = 64;
pub const AUDIT_FEATURE_BITMAP_BACKLOG_LIMIT: u32 = 1;
pub const AUDIT_FEATURE_BITMAP_BACKLOG_WAIT_TIME: u32 = 2;
pub const AUDIT_FEATURE_BITMAP_EXECUTABLE_PATH: u32 = 4;
pub const AUDIT_FEATURE_BITMAP_EXCLUDE_EXTEND: u32 = 8;
pub const AUDIT_FEATURE_BITMAP_SESSIONID_FILTER: u32 = 16;
pub const AUDIT_FEATURE_BITMAP_LOST_RESET: u32 = 32;
pub const AUDIT_FEATURE_BITMAP_FILTER_FS: u32 = 64;
pub const AUDIT_FEATURE_BITMAP_ALL: u32 = 127;
pub const AUDIT_VERSION_LATEST: u32 = 127;
pub const AUDIT_VERSION_BACKLOG_LIMIT: u32 = 1;
pub const AUDIT_VERSION_BACKLOG_WAIT_TIME: u32 = 2;
use crate::Error;
#[derive(Clone, Debug)]
pub struct Handle(ConnectionHandle<AuditMessage>);
impl Handle {
pub(crate) fn new(conn: ConnectionHandle<AuditMessage>) -> Self {
Handle(conn)
}
pub fn request(
&mut self,
message: NetlinkMessage<AuditMessage>,
) -> Result<impl Stream<Item = NetlinkMessage<AuditMessage>>, Error> {
self.0
.request(message, SocketAddr::new(0, 0))
.map_err(|_| Error::RequestFailed)
}
async fn acked_request(&mut self, message: NetlinkMessage<AuditMessage>) -> Result<(), Error> {
let mut response = self.request(message)?;
if let Some(message) = response.next().await {
let (header, payload) = message.into_parts();
if let NetlinkPayload::Error(err_msg) = payload {
Err(Error::NetlinkError(err_msg))
} else {
Err(Error::UnexpectedMessage(NetlinkMessage::new(
header, payload,
)))
}
} else {
Ok(())
}
}
pub async fn add_rule(&mut self, rule: RuleMessage) -> Result<(), Error> {
let mut req = NetlinkMessage::from(AuditMessage::AddRule(rule));
req.header.flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE;
self.acked_request(req).await
}
pub async fn del_rule(&mut self, rule: RuleMessage) -> Result<(), Error> {
let mut req = NetlinkMessage::from(AuditMessage::DelRule(rule));
req.header.flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_NONREC;
self.acked_request(req).await
}
pub fn list_rules(&mut self) -> impl TryStream<Ok = RuleMessage, Error = Error> {
let mut req = NetlinkMessage::from(AuditMessage::ListRules(None));
req.header.flags = NLM_F_REQUEST | NLM_F_DUMP;
match self.request(req) {
Ok(response) => Either::Left(response.map(move |msg| {
let (header, payload) = msg.into_parts();
match payload {
NetlinkPayload::InnerMessage(AuditMessage::ListRules(Some(rule_msg))) => {
Ok(rule_msg)
}
NetlinkPayload::Error(err_msg) => Err(Error::NetlinkError(err_msg)),
_ => Err(Error::UnexpectedMessage(NetlinkMessage::new(
header, payload,
))),
}
})),
Err(e) => Either::Right(future::err::<RuleMessage, Error>(e).into_stream()),
}
}
pub async fn enable_events(&mut self) -> Result<(), Error> {
let mut status = StatusMessage::new();
status.enabled = 1;
status.pid = process::id();
status.mask = AUDIT_STATUS_ENABLED | AUDIT_STATUS_PID;
let mut req = NetlinkMessage::from(AuditMessage::SetStatus(status));
req.header.flags = NLM_F_REQUEST | NLM_F_ACK;
self.acked_request(req).await
}
pub async fn get_status(&mut self) -> Result<StatusMessage, Error> {
let mut req = NetlinkMessage::from(AuditMessage::GetStatus(None));
req.header.flags = NLM_F_REQUEST | NLM_F_DUMP;
let mut request = self.request(req)?;
let response = request.next().await.ok_or(Error::RequestFailed)?;
match response.into_parts() {
(_, NetlinkPayload::InnerMessage(AuditMessage::GetStatus(Some(status)))) => Ok(status),
(header, payload) => Err(Error::UnexpectedMessage(NetlinkMessage::new(
header, payload,
))),
}
}
}