1#![doc = "UNIX socket diagnostics\n"]
2#![allow(clippy::all)]
3#![allow(unused_imports)]
4#![allow(unused_assignments)]
5#![allow(non_snake_case)]
6#![allow(unused_variables)]
7#![allow(irrefutable_let_patterns)]
8#![allow(unreachable_code)]
9#![allow(unreachable_patterns)]
10use crate::builtin::{BuiltinBitfield32, BuiltinNfgenmsg, Nlmsghdr, PushDummy};
11use crate::{
12 consts,
13 traits::{NetlinkRequest, Protocol},
14 utils::*,
15};
16pub const PROTONAME: &str = "unix-diag";
17pub const PROTONAME_CSTR: &CStr = c"unix-diag";
18pub const PROTONUM: u16 = 4u16;
19#[doc = "Flags - defines an integer enumeration, with values for each entry occupying a bit, starting from bit 0, (e.g. 1, 2, 4, 8)"]
20#[derive(Debug, Clone, Copy)]
21pub enum ShowFlags {
22 #[doc = "show name (not path)\n"]
23 Name = 1 << 0,
24 #[doc = "show VFS inode info\n"]
25 Vfs = 1 << 1,
26 #[doc = "show peer socket info\n"]
27 Peer = 1 << 2,
28 #[doc = "show pending connections\n"]
29 Icons = 1 << 3,
30 #[doc = "show skb receive queue len\n"]
31 Rqlen = 1 << 4,
32 #[doc = "show memory info of a socket\n"]
33 Meminfo = 1 << 5,
34 #[doc = "show socket\\'s UID\n"]
35 Uid = 1 << 6,
36}
37impl ShowFlags {
38 pub fn from_value(value: u64) -> Option<Self> {
39 Some(match value {
40 n if n == 1 << 0 => Self::Name,
41 n if n == 1 << 1 => Self::Vfs,
42 n if n == 1 << 2 => Self::Peer,
43 n if n == 1 << 3 => Self::Icons,
44 n if n == 1 << 4 => Self::Rqlen,
45 n if n == 1 << 5 => Self::Meminfo,
46 n if n == 1 << 6 => Self::Uid,
47 _ => return None,
48 })
49 }
50}
51#[repr(C, packed(4))]
52pub struct Req {
53 pub sdiag_family: u8,
54 pub sdiag_protocol: u8,
55 pub pad: u16,
56 #[doc = "States to dump\n"]
57 pub udiag_states: u32,
58 pub udiag_ino: u32,
59 #[doc = "Show flags\n"]
60 pub udiag_show: u32,
61 pub udiag_cookie: [u8; 8usize],
62}
63impl Clone for Req {
64 fn clone(&self) -> Self {
65 Self::new_from_array(*self.as_array())
66 }
67}
68#[doc = "Create zero-initialized struct"]
69impl Default for Req {
70 fn default() -> Self {
71 Self::new()
72 }
73}
74impl Req {
75 #[doc = "Create zero-initialized struct"]
76 pub fn new() -> Self {
77 Self::new_from_array([0u8; Self::len()])
78 }
79 #[doc = "Copy from contents from slice"]
80 pub fn new_from_slice(other: &[u8]) -> Option<Self> {
81 if other.len() != Self::len() {
82 return None;
83 }
84 let mut buf = [0u8; Self::len()];
85 buf.clone_from_slice(other);
86 Some(Self::new_from_array(buf))
87 }
88 #[doc = "Copy from contents from another slice, padding with zeros or truncating when needed"]
89 pub fn new_from_zeroed(other: &[u8]) -> Self {
90 let mut buf = [0u8; Self::len()];
91 let len = buf.len().min(other.len());
92 buf[..len].clone_from_slice(&other[..len]);
93 Self::new_from_array(buf)
94 }
95 pub fn new_from_array(buf: [u8; 24usize]) -> Self {
96 unsafe { std::mem::transmute(buf) }
97 }
98 pub fn as_slice(&self) -> &[u8] {
99 unsafe {
100 let ptr: *const u8 = std::mem::transmute(self as *const Self);
101 std::slice::from_raw_parts(ptr, Self::len())
102 }
103 }
104 pub fn from_slice(buf: &[u8]) -> &Self {
105 assert!(buf.len() >= Self::len());
106 assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
107 unsafe { std::mem::transmute(buf.as_ptr()) }
108 }
109 pub fn as_array(&self) -> &[u8; 24usize] {
110 unsafe { std::mem::transmute(self) }
111 }
112 pub fn from_array(buf: &[u8; 24usize]) -> &Self {
113 assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
114 unsafe { std::mem::transmute(buf) }
115 }
116 pub fn into_array(self) -> [u8; 24usize] {
117 unsafe { std::mem::transmute(self) }
118 }
119 pub const fn len() -> usize {
120 const _: () = assert!(std::mem::size_of::<Req>() == 24usize);
121 24usize
122 }
123}
124impl std::fmt::Debug for Req {
125 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126 fmt.debug_struct("Req")
127 .field("sdiag_family", &self.sdiag_family)
128 .field("sdiag_protocol", &self.sdiag_protocol)
129 .field("pad", &self.pad)
130 .field("udiag_states", &self.udiag_states)
131 .field("udiag_ino", &self.udiag_ino)
132 .field("udiag_show", &self.udiag_show)
133 .field("udiag_cookie", &FormatHex(self.udiag_cookie))
134 .finish()
135 }
136}
137#[repr(C, packed(4))]
138pub struct Msg {
139 pub udiag_family: u8,
140 pub udiag_type: u8,
141 pub udiag_state: u8,
142 pub pad: u8,
143 pub udiag_ino: u32,
144 pub udiag_cookie: [u8; 8usize],
145}
146impl Clone for Msg {
147 fn clone(&self) -> Self {
148 Self::new_from_array(*self.as_array())
149 }
150}
151#[doc = "Create zero-initialized struct"]
152impl Default for Msg {
153 fn default() -> Self {
154 Self::new()
155 }
156}
157impl Msg {
158 #[doc = "Create zero-initialized struct"]
159 pub fn new() -> Self {
160 Self::new_from_array([0u8; Self::len()])
161 }
162 #[doc = "Copy from contents from slice"]
163 pub fn new_from_slice(other: &[u8]) -> Option<Self> {
164 if other.len() != Self::len() {
165 return None;
166 }
167 let mut buf = [0u8; Self::len()];
168 buf.clone_from_slice(other);
169 Some(Self::new_from_array(buf))
170 }
171 #[doc = "Copy from contents from another slice, padding with zeros or truncating when needed"]
172 pub fn new_from_zeroed(other: &[u8]) -> Self {
173 let mut buf = [0u8; Self::len()];
174 let len = buf.len().min(other.len());
175 buf[..len].clone_from_slice(&other[..len]);
176 Self::new_from_array(buf)
177 }
178 pub fn new_from_array(buf: [u8; 16usize]) -> Self {
179 unsafe { std::mem::transmute(buf) }
180 }
181 pub fn as_slice(&self) -> &[u8] {
182 unsafe {
183 let ptr: *const u8 = std::mem::transmute(self as *const Self);
184 std::slice::from_raw_parts(ptr, Self::len())
185 }
186 }
187 pub fn from_slice(buf: &[u8]) -> &Self {
188 assert!(buf.len() >= Self::len());
189 assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
190 unsafe { std::mem::transmute(buf.as_ptr()) }
191 }
192 pub fn as_array(&self) -> &[u8; 16usize] {
193 unsafe { std::mem::transmute(self) }
194 }
195 pub fn from_array(buf: &[u8; 16usize]) -> &Self {
196 assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
197 unsafe { std::mem::transmute(buf) }
198 }
199 pub fn into_array(self) -> [u8; 16usize] {
200 unsafe { std::mem::transmute(self) }
201 }
202 pub const fn len() -> usize {
203 const _: () = assert!(std::mem::size_of::<Msg>() == 16usize);
204 16usize
205 }
206}
207impl std::fmt::Debug for Msg {
208 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209 fmt.debug_struct("Msg")
210 .field("udiag_family", &self.udiag_family)
211 .field("udiag_type", &self.udiag_type)
212 .field("udiag_state", &self.udiag_state)
213 .field("pad", &self.pad)
214 .field("udiag_ino", &self.udiag_ino)
215 .field("udiag_cookie", &FormatHex(self.udiag_cookie))
216 .finish()
217 }
218}
219#[derive(Debug)]
220#[doc = "VFS inode info\n"]
221#[repr(C, packed(4))]
222pub struct Vfs {
223 pub udiag_vfs_ino: u32,
224 pub udiag_vfs_dev: u32,
225}
226impl Clone for Vfs {
227 fn clone(&self) -> Self {
228 Self::new_from_array(*self.as_array())
229 }
230}
231#[doc = "Create zero-initialized struct"]
232impl Default for Vfs {
233 fn default() -> Self {
234 Self::new()
235 }
236}
237impl Vfs {
238 #[doc = "Create zero-initialized struct"]
239 pub fn new() -> Self {
240 Self::new_from_array([0u8; Self::len()])
241 }
242 #[doc = "Copy from contents from slice"]
243 pub fn new_from_slice(other: &[u8]) -> Option<Self> {
244 if other.len() != Self::len() {
245 return None;
246 }
247 let mut buf = [0u8; Self::len()];
248 buf.clone_from_slice(other);
249 Some(Self::new_from_array(buf))
250 }
251 #[doc = "Copy from contents from another slice, padding with zeros or truncating when needed"]
252 pub fn new_from_zeroed(other: &[u8]) -> Self {
253 let mut buf = [0u8; Self::len()];
254 let len = buf.len().min(other.len());
255 buf[..len].clone_from_slice(&other[..len]);
256 Self::new_from_array(buf)
257 }
258 pub fn new_from_array(buf: [u8; 8usize]) -> Self {
259 unsafe { std::mem::transmute(buf) }
260 }
261 pub fn as_slice(&self) -> &[u8] {
262 unsafe {
263 let ptr: *const u8 = std::mem::transmute(self as *const Self);
264 std::slice::from_raw_parts(ptr, Self::len())
265 }
266 }
267 pub fn from_slice(buf: &[u8]) -> &Self {
268 assert!(buf.len() >= Self::len());
269 assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
270 unsafe { std::mem::transmute(buf.as_ptr()) }
271 }
272 pub fn as_array(&self) -> &[u8; 8usize] {
273 unsafe { std::mem::transmute(self) }
274 }
275 pub fn from_array(buf: &[u8; 8usize]) -> &Self {
276 assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
277 unsafe { std::mem::transmute(buf) }
278 }
279 pub fn into_array(self) -> [u8; 8usize] {
280 unsafe { std::mem::transmute(self) }
281 }
282 pub const fn len() -> usize {
283 const _: () = assert!(std::mem::size_of::<Vfs>() == 8usize);
284 8usize
285 }
286}
287#[derive(Debug)]
288#[doc = "Receive queue length info\n"]
289#[repr(C, packed(4))]
290pub struct Rqlen {
291 pub udiag_rqueue: u32,
292 pub udiag_wqueue: u32,
293}
294impl Clone for Rqlen {
295 fn clone(&self) -> Self {
296 Self::new_from_array(*self.as_array())
297 }
298}
299#[doc = "Create zero-initialized struct"]
300impl Default for Rqlen {
301 fn default() -> Self {
302 Self::new()
303 }
304}
305impl Rqlen {
306 #[doc = "Create zero-initialized struct"]
307 pub fn new() -> Self {
308 Self::new_from_array([0u8; Self::len()])
309 }
310 #[doc = "Copy from contents from slice"]
311 pub fn new_from_slice(other: &[u8]) -> Option<Self> {
312 if other.len() != Self::len() {
313 return None;
314 }
315 let mut buf = [0u8; Self::len()];
316 buf.clone_from_slice(other);
317 Some(Self::new_from_array(buf))
318 }
319 #[doc = "Copy from contents from another slice, padding with zeros or truncating when needed"]
320 pub fn new_from_zeroed(other: &[u8]) -> Self {
321 let mut buf = [0u8; Self::len()];
322 let len = buf.len().min(other.len());
323 buf[..len].clone_from_slice(&other[..len]);
324 Self::new_from_array(buf)
325 }
326 pub fn new_from_array(buf: [u8; 8usize]) -> Self {
327 unsafe { std::mem::transmute(buf) }
328 }
329 pub fn as_slice(&self) -> &[u8] {
330 unsafe {
331 let ptr: *const u8 = std::mem::transmute(self as *const Self);
332 std::slice::from_raw_parts(ptr, Self::len())
333 }
334 }
335 pub fn from_slice(buf: &[u8]) -> &Self {
336 assert!(buf.len() >= Self::len());
337 assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
338 unsafe { std::mem::transmute(buf.as_ptr()) }
339 }
340 pub fn as_array(&self) -> &[u8; 8usize] {
341 unsafe { std::mem::transmute(self) }
342 }
343 pub fn from_array(buf: &[u8; 8usize]) -> &Self {
344 assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
345 unsafe { std::mem::transmute(buf) }
346 }
347 pub fn into_array(self) -> [u8; 8usize] {
348 unsafe { std::mem::transmute(self) }
349 }
350 pub const fn len() -> usize {
351 const _: () = assert!(std::mem::size_of::<Rqlen>() == 8usize);
352 8usize
353 }
354}
355#[derive(Clone)]
356pub enum UnixDiagAttrs<'a> {
357 #[doc = "Unix socket sun_path. May or may not contain \\'0\\'.\n"]
358 Name(&'a [u8]),
359 Vfs(Vfs),
360 Peer(u32),
361 Icons(&'a [u8]),
362 Rqlen(Rqlen),
363 Meminfo(&'a [u8]),
364 Shutdown(u8),
365 Uid(u32),
366}
367impl<'a> IterableUnixDiagAttrs<'a> {
368 #[doc = "Unix socket sun_path. May or may not contain \\'0\\'.\n"]
369 pub fn get_name(&self) -> Result<&'a [u8], ErrorContext> {
370 let mut iter = self.clone();
371 iter.pos = 0;
372 for attr in iter {
373 if let Ok(UnixDiagAttrs::Name(val)) = attr {
374 return Ok(val);
375 }
376 }
377 Err(ErrorContext::new_missing(
378 "UnixDiagAttrs",
379 "Name",
380 self.orig_loc,
381 self.buf.as_ptr() as usize,
382 ))
383 }
384 pub fn get_vfs(&self) -> Result<Vfs, ErrorContext> {
385 let mut iter = self.clone();
386 iter.pos = 0;
387 for attr in iter {
388 if let Ok(UnixDiagAttrs::Vfs(val)) = attr {
389 return Ok(val);
390 }
391 }
392 Err(ErrorContext::new_missing(
393 "UnixDiagAttrs",
394 "Vfs",
395 self.orig_loc,
396 self.buf.as_ptr() as usize,
397 ))
398 }
399 pub fn get_peer(&self) -> Result<u32, ErrorContext> {
400 let mut iter = self.clone();
401 iter.pos = 0;
402 for attr in iter {
403 if let Ok(UnixDiagAttrs::Peer(val)) = attr {
404 return Ok(val);
405 }
406 }
407 Err(ErrorContext::new_missing(
408 "UnixDiagAttrs",
409 "Peer",
410 self.orig_loc,
411 self.buf.as_ptr() as usize,
412 ))
413 }
414 pub fn get_icons(&self) -> Result<&'a [u8], ErrorContext> {
415 let mut iter = self.clone();
416 iter.pos = 0;
417 for attr in iter {
418 if let Ok(UnixDiagAttrs::Icons(val)) = attr {
419 return Ok(val);
420 }
421 }
422 Err(ErrorContext::new_missing(
423 "UnixDiagAttrs",
424 "Icons",
425 self.orig_loc,
426 self.buf.as_ptr() as usize,
427 ))
428 }
429 pub fn get_rqlen(&self) -> Result<Rqlen, ErrorContext> {
430 let mut iter = self.clone();
431 iter.pos = 0;
432 for attr in iter {
433 if let Ok(UnixDiagAttrs::Rqlen(val)) = attr {
434 return Ok(val);
435 }
436 }
437 Err(ErrorContext::new_missing(
438 "UnixDiagAttrs",
439 "Rqlen",
440 self.orig_loc,
441 self.buf.as_ptr() as usize,
442 ))
443 }
444 pub fn get_meminfo(&self) -> Result<&'a [u8], ErrorContext> {
445 let mut iter = self.clone();
446 iter.pos = 0;
447 for attr in iter {
448 if let Ok(UnixDiagAttrs::Meminfo(val)) = attr {
449 return Ok(val);
450 }
451 }
452 Err(ErrorContext::new_missing(
453 "UnixDiagAttrs",
454 "Meminfo",
455 self.orig_loc,
456 self.buf.as_ptr() as usize,
457 ))
458 }
459 pub fn get_shutdown(&self) -> Result<u8, ErrorContext> {
460 let mut iter = self.clone();
461 iter.pos = 0;
462 for attr in iter {
463 if let Ok(UnixDiagAttrs::Shutdown(val)) = attr {
464 return Ok(val);
465 }
466 }
467 Err(ErrorContext::new_missing(
468 "UnixDiagAttrs",
469 "Shutdown",
470 self.orig_loc,
471 self.buf.as_ptr() as usize,
472 ))
473 }
474 pub fn get_uid(&self) -> Result<u32, ErrorContext> {
475 let mut iter = self.clone();
476 iter.pos = 0;
477 for attr in iter {
478 if let Ok(UnixDiagAttrs::Uid(val)) = attr {
479 return Ok(val);
480 }
481 }
482 Err(ErrorContext::new_missing(
483 "UnixDiagAttrs",
484 "Uid",
485 self.orig_loc,
486 self.buf.as_ptr() as usize,
487 ))
488 }
489}
490impl UnixDiagAttrs<'_> {
491 pub fn new<'a>(buf: &'a [u8]) -> IterableUnixDiagAttrs<'a> {
492 IterableUnixDiagAttrs::with_loc(buf, buf.as_ptr() as usize)
493 }
494 fn attr_from_type(r#type: u16) -> Option<&'static str> {
495 let res = match r#type {
496 0u16 => "Name",
497 1u16 => "Vfs",
498 2u16 => "Peer",
499 3u16 => "Icons",
500 4u16 => "Rqlen",
501 5u16 => "Meminfo",
502 6u16 => "Shutdown",
503 7u16 => "Uid",
504 _ => return None,
505 };
506 Some(res)
507 }
508}
509#[derive(Clone, Copy, Default)]
510pub struct IterableUnixDiagAttrs<'a> {
511 buf: &'a [u8],
512 pos: usize,
513 orig_loc: usize,
514}
515impl<'a> IterableUnixDiagAttrs<'a> {
516 fn with_loc(buf: &'a [u8], orig_loc: usize) -> Self {
517 Self {
518 buf,
519 pos: 0,
520 orig_loc,
521 }
522 }
523 pub fn get_buf(&self) -> &'a [u8] {
524 self.buf
525 }
526}
527impl<'a> Iterator for IterableUnixDiagAttrs<'a> {
528 type Item = Result<UnixDiagAttrs<'a>, ErrorContext>;
529 fn next(&mut self) -> Option<Self::Item> {
530 let mut pos;
531 let mut r#type;
532 loop {
533 pos = self.pos;
534 r#type = None;
535 if self.buf.len() == self.pos {
536 return None;
537 }
538 let Some((header, next)) = chop_header(self.buf, &mut self.pos) else {
539 self.pos = self.buf.len();
540 break;
541 };
542 r#type = Some(header.r#type);
543 let res = match header.r#type {
544 0u16 => UnixDiagAttrs::Name({
545 let res = Some(next);
546 let Some(val) = res else { break };
547 val
548 }),
549 1u16 => UnixDiagAttrs::Vfs({
550 let res = Some(Vfs::new_from_zeroed(next));
551 let Some(val) = res else { break };
552 val
553 }),
554 2u16 => UnixDiagAttrs::Peer({
555 let res = parse_u32(next);
556 let Some(val) = res else { break };
557 val
558 }),
559 3u16 => UnixDiagAttrs::Icons({
560 let res = Some(next);
561 let Some(val) = res else { break };
562 val
563 }),
564 4u16 => UnixDiagAttrs::Rqlen({
565 let res = Some(Rqlen::new_from_zeroed(next));
566 let Some(val) = res else { break };
567 val
568 }),
569 5u16 => UnixDiagAttrs::Meminfo({
570 let res = Some(next);
571 let Some(val) = res else { break };
572 val
573 }),
574 6u16 => UnixDiagAttrs::Shutdown({
575 let res = parse_u8(next);
576 let Some(val) = res else { break };
577 val
578 }),
579 7u16 => UnixDiagAttrs::Uid({
580 let res = parse_u32(next);
581 let Some(val) = res else { break };
582 val
583 }),
584 n if cfg!(any(test, feature = "deny-unknown-attrs")) => break,
585 n => continue,
586 };
587 return Some(Ok(res));
588 }
589 Some(Err(ErrorContext::new(
590 "UnixDiagAttrs",
591 r#type.and_then(|t| UnixDiagAttrs::attr_from_type(t)),
592 self.orig_loc,
593 self.buf.as_ptr().wrapping_add(pos) as usize,
594 )))
595 }
596}
597impl<'a> std::fmt::Debug for IterableUnixDiagAttrs<'_> {
598 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
599 let mut fmt = f.debug_struct("UnixDiagAttrs");
600 for attr in self.clone() {
601 let attr = match attr {
602 Ok(a) => a,
603 Err(err) => {
604 fmt.finish()?;
605 f.write_str("Err(")?;
606 err.fmt(f)?;
607 return f.write_str(")");
608 }
609 };
610 match attr {
611 UnixDiagAttrs::Name(val) => fmt.field("Name", &FormatBinStr(val)),
612 UnixDiagAttrs::Vfs(val) => fmt.field("Vfs", &val),
613 UnixDiagAttrs::Peer(val) => fmt.field("Peer", &val),
614 UnixDiagAttrs::Icons(val) => fmt.field("Icons", &val),
615 UnixDiagAttrs::Rqlen(val) => fmt.field("Rqlen", &val),
616 UnixDiagAttrs::Meminfo(val) => fmt.field("Meminfo", &val),
617 UnixDiagAttrs::Shutdown(val) => fmt.field("Shutdown", &val),
618 UnixDiagAttrs::Uid(val) => fmt.field("Uid", &val),
619 };
620 }
621 fmt.finish()
622 }
623}
624impl IterableUnixDiagAttrs<'_> {
625 pub fn lookup_attr(
626 &self,
627 offset: usize,
628 missing_type: Option<u16>,
629 ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
630 let mut stack = Vec::new();
631 let cur = ErrorContext::calc_offset(self.orig_loc, self.buf.as_ptr() as usize);
632 if missing_type.is_some() && cur == offset {
633 stack.push(("UnixDiagAttrs", offset));
634 return (
635 stack,
636 missing_type.and_then(|t| UnixDiagAttrs::attr_from_type(t)),
637 );
638 }
639 if cur > offset || cur + self.buf.len() < offset {
640 return (stack, None);
641 }
642 let mut attrs = self.clone();
643 let mut last_off = cur + attrs.pos;
644 while let Some(attr) = attrs.next() {
645 let Ok(attr) = attr else { break };
646 match attr {
647 UnixDiagAttrs::Name(val) => {
648 if last_off == offset {
649 stack.push(("Name", last_off));
650 break;
651 }
652 }
653 UnixDiagAttrs::Vfs(val) => {
654 if last_off == offset {
655 stack.push(("Vfs", last_off));
656 break;
657 }
658 }
659 UnixDiagAttrs::Peer(val) => {
660 if last_off == offset {
661 stack.push(("Peer", last_off));
662 break;
663 }
664 }
665 UnixDiagAttrs::Icons(val) => {
666 if last_off == offset {
667 stack.push(("Icons", last_off));
668 break;
669 }
670 }
671 UnixDiagAttrs::Rqlen(val) => {
672 if last_off == offset {
673 stack.push(("Rqlen", last_off));
674 break;
675 }
676 }
677 UnixDiagAttrs::Meminfo(val) => {
678 if last_off == offset {
679 stack.push(("Meminfo", last_off));
680 break;
681 }
682 }
683 UnixDiagAttrs::Shutdown(val) => {
684 if last_off == offset {
685 stack.push(("Shutdown", last_off));
686 break;
687 }
688 }
689 UnixDiagAttrs::Uid(val) => {
690 if last_off == offset {
691 stack.push(("Uid", last_off));
692 break;
693 }
694 }
695 _ => {}
696 };
697 last_off = cur + attrs.pos;
698 }
699 if !stack.is_empty() {
700 stack.push(("UnixDiagAttrs", cur));
701 }
702 (stack, None)
703 }
704}
705pub struct PushUnixDiagAttrs<Prev: Pusher> {
706 pub(crate) prev: Option<Prev>,
707 pub(crate) header_offset: Option<usize>,
708}
709impl<Prev: Pusher> Pusher for PushUnixDiagAttrs<Prev> {
710 fn as_vec_mut(&mut self) -> &mut Vec<u8> {
711 self.prev.as_mut().unwrap().as_vec_mut()
712 }
713 fn as_vec(&self) -> &Vec<u8> {
714 self.prev.as_ref().unwrap().as_vec()
715 }
716}
717impl<Prev: Pusher> PushUnixDiagAttrs<Prev> {
718 pub fn new(prev: Prev) -> Self {
719 Self {
720 prev: Some(prev),
721 header_offset: None,
722 }
723 }
724 pub fn end_nested(mut self) -> Prev {
725 let mut prev = self.prev.take().unwrap();
726 if let Some(header_offset) = &self.header_offset {
727 finalize_nested_header(prev.as_vec_mut(), *header_offset);
728 }
729 prev
730 }
731 #[doc = "Unix socket sun_path. May or may not contain \\'0\\'.\n"]
732 pub fn push_name(mut self, value: &[u8]) -> Self {
733 push_header(self.as_vec_mut(), 0u16, value.len() as u16);
734 self.as_vec_mut().extend(value);
735 self
736 }
737 pub fn push_vfs(mut self, value: Vfs) -> Self {
738 push_header(self.as_vec_mut(), 1u16, value.as_slice().len() as u16);
739 self.as_vec_mut().extend(value.as_slice());
740 self
741 }
742 pub fn push_peer(mut self, value: u32) -> Self {
743 push_header(self.as_vec_mut(), 2u16, 4 as u16);
744 self.as_vec_mut().extend(value.to_ne_bytes());
745 self
746 }
747 pub fn push_icons(mut self, value: &[u8]) -> Self {
748 push_header(self.as_vec_mut(), 3u16, value.len() as u16);
749 self.as_vec_mut().extend(value);
750 self
751 }
752 pub fn push_rqlen(mut self, value: Rqlen) -> Self {
753 push_header(self.as_vec_mut(), 4u16, value.as_slice().len() as u16);
754 self.as_vec_mut().extend(value.as_slice());
755 self
756 }
757 pub fn push_meminfo(mut self, value: &[u8]) -> Self {
758 push_header(self.as_vec_mut(), 5u16, value.len() as u16);
759 self.as_vec_mut().extend(value);
760 self
761 }
762 pub fn push_shutdown(mut self, value: u8) -> Self {
763 push_header(self.as_vec_mut(), 6u16, 1 as u16);
764 self.as_vec_mut().extend(value.to_ne_bytes());
765 self
766 }
767 pub fn push_uid(mut self, value: u32) -> Self {
768 push_header(self.as_vec_mut(), 7u16, 4 as u16);
769 self.as_vec_mut().extend(value.to_ne_bytes());
770 self
771 }
772}
773impl<Prev: Pusher> Drop for PushUnixDiagAttrs<Prev> {
774 fn drop(&mut self) {
775 if let Some(prev) = &mut self.prev {
776 if let Some(header_offset) = &self.header_offset {
777 finalize_nested_header(prev.as_vec_mut(), *header_offset);
778 }
779 }
780 }
781}
782#[doc = ""]
783#[derive(Debug)]
784pub struct OpUnixDiagDump<'r> {
785 request: Request<'r>,
786}
787impl<'r> OpUnixDiagDump<'r> {
788 pub fn new(mut request: Request<'r>, header: &Req) -> Self {
789 Self::write_header(request.buf_mut(), header);
790 Self {
791 request: request.set_dump(),
792 }
793 }
794 pub fn encode_request<'buf>(
795 buf: &'buf mut Vec<u8>,
796 header: &Req,
797 ) -> PushUnixDiagAttrs<&'buf mut Vec<u8>> {
798 Self::write_header(buf, header);
799 PushUnixDiagAttrs::new(buf)
800 }
801 pub fn encode(&mut self) -> PushUnixDiagAttrs<&mut Vec<u8>> {
802 PushUnixDiagAttrs::new(self.request.buf_mut())
803 }
804 pub fn into_encoder(self) -> PushUnixDiagAttrs<RequestBuf<'r>> {
805 PushUnixDiagAttrs::new(self.request.buf)
806 }
807 pub fn decode_request<'a>(buf: &'a [u8]) -> (Req, IterableUnixDiagAttrs<'a>) {
808 let (header, attrs) = buf.split_at(buf.len().min(Req::len()));
809 (
810 Req::new_from_slice(header).unwrap_or_default(),
811 IterableUnixDiagAttrs::with_loc(attrs, buf.as_ptr() as usize),
812 )
813 }
814 fn decode_reply<'a>(buf: &'a [u8]) -> (Msg, IterableUnixDiagAttrs<'a>) {
815 let (header, attrs) = buf.split_at(buf.len().min(Msg::len()));
816 (
817 Msg::new_from_slice(header).unwrap_or_default(),
818 IterableUnixDiagAttrs::with_loc(attrs, buf.as_ptr() as usize),
819 )
820 }
821 fn write_header<Prev: Pusher>(prev: &mut Prev, header: &Req) {
822 prev.as_vec_mut().extend(header.as_slice());
823 }
824}
825impl NetlinkRequest for OpUnixDiagDump<'_> {
826 fn protocol(&self) -> Protocol {
827 Protocol::Raw {
828 protonum: 4u16,
829 request_type: 20u16,
830 }
831 }
832 fn flags(&self) -> u16 {
833 self.request.flags
834 }
835 fn payload(&self) -> &[u8] {
836 self.request.buf()
837 }
838 type ReplyType<'buf> = (Msg, IterableUnixDiagAttrs<'buf>);
839 fn decode_reply<'buf>(buf: &'buf [u8]) -> Self::ReplyType<'buf> {
840 Self::decode_reply(buf)
841 }
842 fn lookup(
843 buf: &[u8],
844 offset: usize,
845 missing_type: Option<u16>,
846 ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
847 Self::decode_request(buf)
848 .1
849 .lookup_attr(offset, missing_type)
850 }
851}
852#[derive(Debug)]
853pub struct ChainedFinal<'a> {
854 inner: Chained<'a>,
855}
856#[derive(Debug)]
857pub struct Chained<'a> {
858 buf: RequestBuf<'a>,
859 first_seq: u32,
860 lookups: Vec<(&'static str, LookupFn)>,
861 last_header_offset: usize,
862 last_kind: Option<RequestInfo>,
863}
864impl<'a> ChainedFinal<'a> {
865 pub fn into_chained(self) -> Chained<'a> {
866 self.inner
867 }
868 pub fn buf(&self) -> &Vec<u8> {
869 self.inner.buf()
870 }
871 pub fn buf_mut(&mut self) -> &mut Vec<u8> {
872 self.inner.buf_mut()
873 }
874 fn get_index(&self, seq: u32) -> Option<u32> {
875 let min = self.inner.first_seq;
876 let max = min.wrapping_add(self.inner.lookups.len() as u32);
877 return if min <= max {
878 (min..max).contains(&seq).then(|| seq - min)
879 } else if min <= seq {
880 Some(seq - min)
881 } else if seq < max {
882 Some(u32::MAX - min + seq)
883 } else {
884 None
885 };
886 }
887}
888impl crate::traits::NetlinkChained for ChainedFinal<'_> {
889 fn protonum(&self) -> u16 {
890 PROTONUM
891 }
892 fn payload(&self) -> &[u8] {
893 self.buf()
894 }
895 fn chain_len(&self) -> usize {
896 self.inner.lookups.len()
897 }
898 fn get_index(&self, seq: u32) -> Option<usize> {
899 self.get_index(seq).map(|n| n as usize)
900 }
901 fn name(&self, index: usize) -> &'static str {
902 self.inner.lookups[index].0
903 }
904 fn lookup(&self, index: usize) -> LookupFn {
905 self.inner.lookups[index].1
906 }
907}
908impl Chained<'static> {
909 pub fn new(first_seq: u32) -> Self {
910 Self::new_from_buf(Vec::new(), first_seq)
911 }
912 pub fn new_from_buf(buf: Vec<u8>, first_seq: u32) -> Self {
913 Self {
914 buf: RequestBuf::Own(buf),
915 first_seq,
916 lookups: Vec::new(),
917 last_header_offset: 0,
918 last_kind: None,
919 }
920 }
921 pub fn into_buf(self) -> Vec<u8> {
922 match self.buf {
923 RequestBuf::Own(buf) => buf,
924 _ => unreachable!(),
925 }
926 }
927}
928impl<'a> Chained<'a> {
929 pub fn new_with_buf(buf: &'a mut Vec<u8>, first_seq: u32) -> Self {
930 Self {
931 buf: RequestBuf::Ref(buf),
932 first_seq,
933 lookups: Vec::new(),
934 last_header_offset: 0,
935 last_kind: None,
936 }
937 }
938 pub fn finalize(mut self) -> ChainedFinal<'a> {
939 self.update_header();
940 ChainedFinal { inner: self }
941 }
942 pub fn request(&mut self) -> Request<'_> {
943 self.update_header();
944 self.last_header_offset = self.buf().len();
945 self.buf_mut().extend_from_slice(Nlmsghdr::new().as_slice());
946 let mut request = Request::new_extend(self.buf.buf_mut());
947 self.last_kind = None;
948 request.writeback = Some(&mut self.last_kind);
949 request
950 }
951 pub fn buf(&self) -> &Vec<u8> {
952 self.buf.buf()
953 }
954 pub fn buf_mut(&mut self) -> &mut Vec<u8> {
955 self.buf.buf_mut()
956 }
957 fn update_header(&mut self) {
958 let Some(RequestInfo {
959 protocol,
960 flags,
961 name,
962 lookup,
963 }) = self.last_kind
964 else {
965 if !self.buf().is_empty() {
966 assert_eq!(self.last_header_offset + Nlmsghdr::len(), self.buf().len());
967 self.buf.buf_mut().truncate(self.last_header_offset);
968 }
969 return;
970 };
971 let header_offset = self.last_header_offset;
972 let request_type = match protocol {
973 Protocol::Raw { request_type, .. } => request_type,
974 Protocol::Generic(_) => unreachable!(),
975 };
976 let index = self.lookups.len();
977 let seq = self.first_seq.wrapping_add(index as u32);
978 self.lookups.push((name, lookup));
979 let buf = self.buf_mut();
980 align(buf);
981 let header = Nlmsghdr {
982 len: (buf.len() - header_offset) as u32,
983 r#type: request_type,
984 flags: flags | consts::NLM_F_REQUEST as u16 | consts::NLM_F_ACK as u16,
985 seq,
986 pid: 0,
987 };
988 buf[header_offset..(header_offset + 16)].clone_from_slice(header.as_slice());
989 }
990}
991use crate::traits::LookupFn;
992use crate::utils::RequestBuf;
993#[derive(Debug)]
994pub struct Request<'buf> {
995 buf: RequestBuf<'buf>,
996 flags: u16,
997 writeback: Option<&'buf mut Option<RequestInfo>>,
998}
999#[allow(unused)]
1000#[derive(Debug, Clone)]
1001pub struct RequestInfo {
1002 protocol: Protocol,
1003 flags: u16,
1004 name: &'static str,
1005 lookup: LookupFn,
1006}
1007impl Request<'static> {
1008 pub fn new() -> Self {
1009 Self::new_from_buf(Vec::new())
1010 }
1011 pub fn new_from_buf(buf: Vec<u8>) -> Self {
1012 Self {
1013 flags: 0,
1014 buf: RequestBuf::Own(buf),
1015 writeback: None,
1016 }
1017 }
1018 pub fn into_buf(self) -> Vec<u8> {
1019 match self.buf {
1020 RequestBuf::Own(buf) => buf,
1021 _ => unreachable!(),
1022 }
1023 }
1024}
1025impl<'buf> Request<'buf> {
1026 pub fn new_with_buf(buf: &'buf mut Vec<u8>) -> Self {
1027 buf.clear();
1028 Self::new_extend(buf)
1029 }
1030 pub fn new_extend(buf: &'buf mut Vec<u8>) -> Self {
1031 Self {
1032 flags: 0,
1033 buf: RequestBuf::Ref(buf),
1034 writeback: None,
1035 }
1036 }
1037 fn do_writeback(&mut self, protocol: Protocol, name: &'static str, lookup: LookupFn) {
1038 let Some(writeback) = &mut self.writeback else {
1039 return;
1040 };
1041 **writeback = Some(RequestInfo {
1042 protocol,
1043 flags: self.flags,
1044 name,
1045 lookup,
1046 })
1047 }
1048 pub fn buf(&self) -> &Vec<u8> {
1049 self.buf.buf()
1050 }
1051 pub fn buf_mut(&mut self) -> &mut Vec<u8> {
1052 self.buf.buf_mut()
1053 }
1054 #[doc = "Set `NLM_F_CREATE` flag"]
1055 pub fn set_create(mut self) -> Self {
1056 self.flags |= consts::NLM_F_CREATE as u16;
1057 self
1058 }
1059 #[doc = "Set `NLM_F_EXCL` flag"]
1060 pub fn set_excl(mut self) -> Self {
1061 self.flags |= consts::NLM_F_EXCL as u16;
1062 self
1063 }
1064 #[doc = "Set `NLM_F_REPLACE` flag"]
1065 pub fn set_replace(mut self) -> Self {
1066 self.flags |= consts::NLM_F_REPLACE as u16;
1067 self
1068 }
1069 #[doc = "Set `NLM_F_CREATE` and `NLM_F_REPLACE` flag"]
1070 pub fn set_change(self) -> Self {
1071 self.set_create().set_replace()
1072 }
1073 #[doc = "Set `NLM_F_APPEND` flag"]
1074 pub fn set_append(mut self) -> Self {
1075 self.flags |= consts::NLM_F_APPEND as u16;
1076 self
1077 }
1078 #[doc = "Set `self.flags |= flags`"]
1079 pub fn set_flags(mut self, flags: u16) -> Self {
1080 self.flags |= flags;
1081 self
1082 }
1083 #[doc = "Set `self.flags ^= self.flags & flags`"]
1084 pub fn unset_flags(mut self, flags: u16) -> Self {
1085 self.flags ^= self.flags & flags;
1086 self
1087 }
1088 #[doc = "Set `NLM_F_DUMP` flag"]
1089 fn set_dump(mut self) -> Self {
1090 self.flags |= consts::NLM_F_DUMP as u16;
1091 self
1092 }
1093 #[doc = ""]
1094 pub fn op_unix_diag_dump(self, header: &Req) -> OpUnixDiagDump<'buf> {
1095 let mut res = OpUnixDiagDump::new(self, header);
1096 res.request
1097 .do_writeback(res.protocol(), "op-unix-diag-dump", OpUnixDiagDump::lookup);
1098 res
1099 }
1100}