netlink_packet/netlink/
message.rs1use crate::constants::*;
2use failure::ResultExt;
3
4use crate::{
5 AckMessage, DecodeError, Emitable, EncodeError, ErrorBuffer, ErrorMessage, NetlinkBuffer,
6 NetlinkHeader, Parseable,
7};
8
9#[cfg(feature = "rtnetlink")]
10use crate::RtnlMessage;
11
12#[cfg(feature = "audit")]
13use crate::AuditMessage;
14
15#[derive(Debug, PartialEq, Eq, Clone)]
39pub struct NetlinkMessage {
40 header: NetlinkHeader,
41 payload: NetlinkPayload,
42}
43
44#[derive(Debug, PartialEq, Eq, Clone)]
45pub enum NetlinkPayload {
46 Done,
47 Error(ErrorMessage),
48 Ack(AckMessage),
49 Noop,
50 Overrun(Vec<u8>),
51 #[cfg(feature = "rtnetlink")]
52 Rtnl(RtnlMessage),
53 #[cfg(feature = "audit")]
54 Audit(AuditMessage),
55 #[cfg(not(any(feature = "rtnetlink", feature = "audit")))]
56 #[doc(hidden)]
57 __Default,
58}
59
60impl NetlinkPayload {
61 pub fn message_type(&self) -> u16 {
62 use self::NetlinkPayload::*;
63
64 match self {
65 Noop => NLMSG_NOOP,
66 Done => NLMSG_DONE,
67 Error(_) | Ack(_) => NLMSG_ERROR,
68 Overrun(_) => NLMSG_OVERRUN,
69 #[cfg(feature = "rtnetlink")]
70 Rtnl(ref msg) => msg.message_type(),
71 #[cfg(feature = "audit")]
72 Audit(ref msg) => msg.message_type(),
73 #[cfg(not(any(feature = "rtnetlink", feature = "audit")))]
74 _ => 0,
75 }
76 }
77
78 #[cfg(feature = "rtnetlink")]
79 pub fn is_rtnl(&self) -> bool {
80 if let NetlinkPayload::Rtnl(_) = *self {
81 true
82 } else {
83 false
84 }
85 }
86
87 #[cfg(feature = "audit")]
88 pub fn is_audit(&self) -> bool {
89 if let NetlinkPayload::Audit(_) = *self {
90 true
91 } else {
92 false
93 }
94 }
95
96 pub fn is_done(&self) -> bool {
97 *self == NetlinkPayload::Done
98 }
99
100 pub fn is_noop(&self) -> bool {
101 *self == NetlinkPayload::Noop
102 }
103
104 pub fn is_overrun(&self) -> bool {
105 if let NetlinkPayload::Overrun(_) = *self {
106 true
107 } else {
108 false
109 }
110 }
111
112 pub fn is_error(&self) -> bool {
113 if let NetlinkPayload::Error(_) = *self {
114 true
115 } else {
116 false
117 }
118 }
119
120 pub fn is_ack(&self) -> bool {
121 if let NetlinkPayload::Ack(_) = *self {
122 true
123 } else {
124 false
125 }
126 }
127}
128
129impl From<NetlinkPayload> for NetlinkMessage {
130 fn from(payload: NetlinkPayload) -> Self {
131 NetlinkMessage {
132 header: NetlinkHeader::default(),
133 payload,
134 }
135 }
136}
137
138#[cfg(feature = "rtnetlink")]
139impl From<RtnlMessage> for NetlinkMessage {
140 fn from(msg: RtnlMessage) -> Self {
141 NetlinkMessage::from(NetlinkPayload::Rtnl(msg))
142 }
143}
144
145#[cfg(feature = "audit")]
146impl From<AuditMessage> for NetlinkMessage {
147 fn from(msg: AuditMessage) -> Self {
148 NetlinkMessage::from(NetlinkPayload::Audit(msg))
149 }
150}
151
152impl NetlinkMessage {
153 pub fn new(header: NetlinkHeader, payload: NetlinkPayload) -> Self {
154 NetlinkMessage { header, payload }
155 }
156
157 pub fn into_parts(self) -> (NetlinkHeader, NetlinkPayload) {
158 (self.header, self.payload)
159 }
160
161 pub fn payload(&self) -> &NetlinkPayload {
162 &self.payload
163 }
164
165 pub fn payload_mut(&mut self) -> &mut NetlinkPayload {
166 &mut self.payload
167 }
168
169 pub fn header(&self) -> &NetlinkHeader {
170 &self.header
171 }
172
173 pub fn header_mut(&mut self) -> &mut NetlinkHeader {
174 &mut self.header
175 }
176
177 #[allow(clippy::wrong_self_convention)]
182 pub fn to_bytes(&mut self, buffer: &mut [u8]) -> Result<usize, EncodeError> {
183 self.finalize();
184 if self.header().length() as usize > buffer.len() {
185 Err(EncodeError::from("buffer exhausted"))
186 } else {
187 self.emit(buffer);
188 Ok(self.header().length() as usize)
189 }
190 }
191
192 pub fn from_bytes(buffer: &[u8]) -> Result<Self, DecodeError> {
194 Ok(NetlinkBuffer::new_checked(&buffer)
195 .context("failed to parse netlink packet")?
196 .parse()
197 .context("failed to parse netlink packet")?)
198 }
199
200 pub fn is_done(&self) -> bool {
203 self.payload().is_done()
204 }
205
206 pub fn is_noop(&self) -> bool {
209 self.payload().is_noop()
210 }
211
212 pub fn is_overrun(&self) -> bool {
215 self.payload().is_overrun()
216 }
217
218 pub fn is_error(&self) -> bool {
221 self.payload().is_error()
222 }
223
224 pub fn is_ack(&self) -> bool {
227 self.payload().is_ack()
228 }
229
230 #[cfg(feature = "rtnetlink")]
231 pub fn is_rtnl(&self) -> bool {
232 self.payload().is_rtnl()
233 }
234
235 #[cfg(feature = "audit")]
236 pub fn is_audit(&self) -> bool {
237 self.payload().is_audit()
238 }
239
240 pub fn finalize(&mut self) {
250 *self.header.length_mut() = self.buffer_len() as u32;
251 *self.header.message_type_mut() = self.payload.message_type();
252 }
253}
254
255impl<'buffer, T: AsRef<[u8]> + 'buffer> Parseable<NetlinkMessage> for NetlinkBuffer<&'buffer T> {
256 fn parse(&self) -> Result<NetlinkMessage, DecodeError> {
257 use self::NetlinkPayload::*;
258 let header = <Self as Parseable<NetlinkHeader>>::parse(self)
259 .context("failed to parse netlink header")?;
260
261 let payload = match header.message_type() {
262 NLMSG_ERROR => {
263 let msg: ErrorMessage = ErrorBuffer::new(&self.payload())
264 .parse()
265 .context("failed to parse NLMSG_ERROR")?;
266 if msg.code >= 0 {
267 Ack(msg as AckMessage)
268 } else {
269 Error(msg)
270 }
271 }
272 NLMSG_NOOP => Noop,
273 NLMSG_DONE => Done,
274
275 #[cfg(feature = "rtnetlink")]
276 message_type => {
277 NetlinkPayload::Rtnl(RtnlMessage::parse(message_type, &self.payload())?)
278 }
279
280 #[cfg(feature = "audit")]
281 message_type => {
282 NetlinkPayload::Audit(AuditMessage::parse(message_type, &self.payload())?)
283 }
284
285 #[cfg(not(any(feature = "rtnetlink", feature = "audit")))]
286 _ => __Default,
287 };
288 Ok(NetlinkMessage { header, payload })
289 }
290}
291
292impl Emitable for NetlinkMessage {
293 fn buffer_len(&self) -> usize {
294 use self::NetlinkPayload::*;
295 let payload_len = match self.payload {
296 Noop | Done => 0,
297 Overrun(ref bytes) => bytes.len(),
298 Error(ref msg) => msg.buffer_len(),
299 Ack(ref msg) => msg.buffer_len(),
300
301 #[cfg(feature = "rtnetlink")]
302 Rtnl(ref msg) => msg.buffer_len(),
303
304 #[cfg(feature = "audit")]
305 Audit(ref msg) => msg.buffer_len(),
306
307 #[cfg(not(any(feature = "rtnetlink", feature = "audit")))]
308 __Default => 0,
309 };
310
311 self.header.buffer_len() + payload_len
312 }
313
314 fn emit(&self, buffer: &mut [u8]) {
315 use self::NetlinkPayload::*;
316
317 self.header.emit(buffer);
318
319 let buffer = &mut buffer[self.header.buffer_len()..];
320 match self.payload {
321 Noop | Done => {}
322 Overrun(ref bytes) => buffer.copy_from_slice(bytes),
323 Error(ref msg) => msg.emit(buffer),
324 Ack(ref msg) => msg.emit(buffer),
325
326 #[cfg(feature = "rtnetlink")]
327 Rtnl(ref msg) => msg.emit(buffer),
328
329 #[cfg(feature = "audit")]
330 Audit(ref msg) => msg.emit(buffer),
331
332 #[cfg(not(any(feature = "rtnetlink", feature = "audit")))]
333 __Default => {}
334 }
335 }
336}