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 = "VFS inode info"]
20#[doc = "Receive queue length info"]
21#[doc = "Flags - defines an integer enumeration, with values for each entry occupying a bit, starting from bit 0, (e.g. 1, 2, 4, 8)"]
22#[derive(Debug, Clone, Copy)]
23pub enum ShowFlags {
24 #[doc = "show name (not path)"]
25 Name = 1 << 0,
26 #[doc = "show VFS inode info"]
27 Vfs = 1 << 1,
28 #[doc = "show peer socket info"]
29 Peer = 1 << 2,
30 #[doc = "show pending connections"]
31 Icons = 1 << 3,
32 #[doc = "show skb receive queue len"]
33 Rqlen = 1 << 4,
34 #[doc = "show memory info of a socket"]
35 Meminfo = 1 << 5,
36 #[doc = "show socket's UID"]
37 Uid = 1 << 6,
38}
39impl ShowFlags {
40 pub fn from_value(value: u64) -> Option<Self> {
41 Some(match value {
42 n if n == 1 << 0 => Self::Name,
43 n if n == 1 << 1 => Self::Vfs,
44 n if n == 1 << 2 => Self::Peer,
45 n if n == 1 << 3 => Self::Icons,
46 n if n == 1 << 4 => Self::Rqlen,
47 n if n == 1 << 5 => Self::Meminfo,
48 n if n == 1 << 6 => Self::Uid,
49 _ => return None,
50 })
51 }
52}
53#[repr(C, packed(4))]
54pub struct Req {
55 pub sdiag_family: u8,
56 pub sdiag_protocol: u8,
57 pub pad: u16,
58 #[doc = "States to dump"]
59 pub udiag_states: u32,
60 pub udiag_ino: u32,
61 #[doc = "Show flags"]
62 pub udiag_show: u32,
63 pub udiag_cookie: [u8; 8usize],
64}
65impl Clone for Req {
66 fn clone(&self) -> Self {
67 Self::new_from_array(*self.as_array())
68 }
69}
70#[doc = "Create zero-initialized struct"]
71impl Default for Req {
72 fn default() -> Self {
73 Self::new()
74 }
75}
76impl Req {
77 #[doc = "Create zero-initialized struct"]
78 pub fn new() -> Self {
79 Self::new_from_array([0u8; Self::len()])
80 }
81 #[doc = "Copy from contents from slice"]
82 pub fn new_from_slice(other: &[u8]) -> Option<Self> {
83 if other.len() != Self::len() {
84 return None;
85 }
86 let mut buf = [0u8; Self::len()];
87 buf.clone_from_slice(other);
88 Some(Self::new_from_array(buf))
89 }
90 #[doc = "Copy from contents from another slice, padding with zeros or truncating when needed"]
91 pub fn new_from_zeroed(other: &[u8]) -> Self {
92 let mut buf = [0u8; Self::len()];
93 let len = buf.len().min(other.len());
94 buf[..len].clone_from_slice(&other[..len]);
95 Self::new_from_array(buf)
96 }
97 pub fn new_from_array(buf: [u8; 24usize]) -> Self {
98 unsafe { std::mem::transmute(buf) }
99 }
100 pub fn as_slice(&self) -> &[u8] {
101 unsafe {
102 let ptr: *const u8 = std::mem::transmute(self as *const Self);
103 std::slice::from_raw_parts(ptr, Self::len())
104 }
105 }
106 pub fn from_slice(buf: &[u8]) -> &Self {
107 assert!(buf.len() >= Self::len());
108 assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
109 unsafe { std::mem::transmute(buf.as_ptr()) }
110 }
111 pub fn as_array(&self) -> &[u8; 24usize] {
112 unsafe { std::mem::transmute(self) }
113 }
114 pub fn from_array(buf: &[u8; 24usize]) -> &Self {
115 assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
116 unsafe { std::mem::transmute(buf) }
117 }
118 pub fn into_array(self) -> [u8; 24usize] {
119 unsafe { std::mem::transmute(self) }
120 }
121 pub const fn len() -> usize {
122 const _: () = assert!(std::mem::size_of::<Req>() == 24usize);
123 24usize
124 }
125}
126impl std::fmt::Debug for Req {
127 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128 fmt.debug_struct("Req")
129 .field("sdiag_family", &self.sdiag_family)
130 .field("sdiag_protocol", &self.sdiag_protocol)
131 .field("pad", &self.pad)
132 .field("udiag_states", &self.udiag_states)
133 .field("udiag_ino", &self.udiag_ino)
134 .field("udiag_show", &self.udiag_show)
135 .field("udiag_cookie", &FormatHex(self.udiag_cookie))
136 .finish()
137 }
138}
139#[repr(C, packed(4))]
140pub struct Msg {
141 pub udiag_family: u8,
142 pub udiag_type: u8,
143 pub udiag_state: u8,
144 pub pad: u8,
145 pub udiag_ino: u32,
146 pub udiag_cookie: [u8; 8usize],
147}
148impl Clone for Msg {
149 fn clone(&self) -> Self {
150 Self::new_from_array(*self.as_array())
151 }
152}
153#[doc = "Create zero-initialized struct"]
154impl Default for Msg {
155 fn default() -> Self {
156 Self::new()
157 }
158}
159impl Msg {
160 #[doc = "Create zero-initialized struct"]
161 pub fn new() -> Self {
162 Self::new_from_array([0u8; Self::len()])
163 }
164 #[doc = "Copy from contents from slice"]
165 pub fn new_from_slice(other: &[u8]) -> Option<Self> {
166 if other.len() != Self::len() {
167 return None;
168 }
169 let mut buf = [0u8; Self::len()];
170 buf.clone_from_slice(other);
171 Some(Self::new_from_array(buf))
172 }
173 #[doc = "Copy from contents from another slice, padding with zeros or truncating when needed"]
174 pub fn new_from_zeroed(other: &[u8]) -> Self {
175 let mut buf = [0u8; Self::len()];
176 let len = buf.len().min(other.len());
177 buf[..len].clone_from_slice(&other[..len]);
178 Self::new_from_array(buf)
179 }
180 pub fn new_from_array(buf: [u8; 16usize]) -> Self {
181 unsafe { std::mem::transmute(buf) }
182 }
183 pub fn as_slice(&self) -> &[u8] {
184 unsafe {
185 let ptr: *const u8 = std::mem::transmute(self as *const Self);
186 std::slice::from_raw_parts(ptr, Self::len())
187 }
188 }
189 pub fn from_slice(buf: &[u8]) -> &Self {
190 assert!(buf.len() >= Self::len());
191 assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
192 unsafe { std::mem::transmute(buf.as_ptr()) }
193 }
194 pub fn as_array(&self) -> &[u8; 16usize] {
195 unsafe { std::mem::transmute(self) }
196 }
197 pub fn from_array(buf: &[u8; 16usize]) -> &Self {
198 assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
199 unsafe { std::mem::transmute(buf) }
200 }
201 pub fn into_array(self) -> [u8; 16usize] {
202 unsafe { std::mem::transmute(self) }
203 }
204 pub const fn len() -> usize {
205 const _: () = assert!(std::mem::size_of::<Msg>() == 16usize);
206 16usize
207 }
208}
209impl std::fmt::Debug for Msg {
210 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
211 fmt.debug_struct("Msg")
212 .field("udiag_family", &self.udiag_family)
213 .field("udiag_type", &self.udiag_type)
214 .field("udiag_state", &self.udiag_state)
215 .field("pad", &self.pad)
216 .field("udiag_ino", &self.udiag_ino)
217 .field("udiag_cookie", &FormatHex(self.udiag_cookie))
218 .finish()
219 }
220}
221#[derive(Debug)]
222#[repr(C, packed(4))]
223pub struct Vfs {
224 pub udiag_vfs_ino: u32,
225 pub udiag_vfs_dev: u32,
226}
227impl Clone for Vfs {
228 fn clone(&self) -> Self {
229 Self::new_from_array(*self.as_array())
230 }
231}
232#[doc = "Create zero-initialized struct"]
233impl Default for Vfs {
234 fn default() -> Self {
235 Self::new()
236 }
237}
238impl Vfs {
239 #[doc = "Create zero-initialized struct"]
240 pub fn new() -> Self {
241 Self::new_from_array([0u8; Self::len()])
242 }
243 #[doc = "Copy from contents from slice"]
244 pub fn new_from_slice(other: &[u8]) -> Option<Self> {
245 if other.len() != Self::len() {
246 return None;
247 }
248 let mut buf = [0u8; Self::len()];
249 buf.clone_from_slice(other);
250 Some(Self::new_from_array(buf))
251 }
252 #[doc = "Copy from contents from another slice, padding with zeros or truncating when needed"]
253 pub fn new_from_zeroed(other: &[u8]) -> Self {
254 let mut buf = [0u8; Self::len()];
255 let len = buf.len().min(other.len());
256 buf[..len].clone_from_slice(&other[..len]);
257 Self::new_from_array(buf)
258 }
259 pub fn new_from_array(buf: [u8; 8usize]) -> Self {
260 unsafe { std::mem::transmute(buf) }
261 }
262 pub fn as_slice(&self) -> &[u8] {
263 unsafe {
264 let ptr: *const u8 = std::mem::transmute(self as *const Self);
265 std::slice::from_raw_parts(ptr, Self::len())
266 }
267 }
268 pub fn from_slice(buf: &[u8]) -> &Self {
269 assert!(buf.len() >= Self::len());
270 assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
271 unsafe { std::mem::transmute(buf.as_ptr()) }
272 }
273 pub fn as_array(&self) -> &[u8; 8usize] {
274 unsafe { std::mem::transmute(self) }
275 }
276 pub fn from_array(buf: &[u8; 8usize]) -> &Self {
277 assert!(buf.as_ptr() as usize % std::mem::align_of::<Self>() == 0);
278 unsafe { std::mem::transmute(buf) }
279 }
280 pub fn into_array(self) -> [u8; 8usize] {
281 unsafe { std::mem::transmute(self) }
282 }
283 pub const fn len() -> usize {
284 const _: () = assert!(std::mem::size_of::<Vfs>() == 8usize);
285 8usize
286 }
287}
288#[derive(Debug)]
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'\\."]
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'\\."]
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 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 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 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 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 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 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 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 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 pos = self.pos;
531 let mut r#type;
532 loop {
533 r#type = None;
534 if self.buf.len() == self.pos {
535 return None;
536 }
537 let Some((header, next)) = chop_header(self.buf, &mut self.pos) else {
538 break;
539 };
540 r#type = Some(header.r#type);
541 let res = match header.r#type {
542 0u16 => UnixDiagAttrs::Name({
543 let res = Some(next);
544 let Some(val) = res else { break };
545 val
546 }),
547 1u16 => UnixDiagAttrs::Vfs({
548 let res = Some(Vfs::new_from_zeroed(next));
549 let Some(val) = res else { break };
550 val
551 }),
552 2u16 => UnixDiagAttrs::Peer({
553 let res = parse_u32(next);
554 let Some(val) = res else { break };
555 val
556 }),
557 3u16 => UnixDiagAttrs::Icons({
558 let res = Some(next);
559 let Some(val) = res else { break };
560 val
561 }),
562 4u16 => UnixDiagAttrs::Rqlen({
563 let res = Some(Rqlen::new_from_zeroed(next));
564 let Some(val) = res else { break };
565 val
566 }),
567 5u16 => UnixDiagAttrs::Meminfo({
568 let res = Some(next);
569 let Some(val) = res else { break };
570 val
571 }),
572 6u16 => UnixDiagAttrs::Shutdown({
573 let res = parse_u8(next);
574 let Some(val) = res else { break };
575 val
576 }),
577 7u16 => UnixDiagAttrs::Uid({
578 let res = parse_u32(next);
579 let Some(val) = res else { break };
580 val
581 }),
582 n if cfg!(any(test, feature = "deny-unknown-attrs")) => break,
583 n => continue,
584 };
585 return Some(Ok(res));
586 }
587 Some(Err(ErrorContext::new(
588 "UnixDiagAttrs",
589 r#type.and_then(|t| UnixDiagAttrs::attr_from_type(t)),
590 self.orig_loc,
591 self.buf.as_ptr().wrapping_add(pos) as usize,
592 )))
593 }
594}
595impl<'a> std::fmt::Debug for IterableUnixDiagAttrs<'_> {
596 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
597 let mut fmt = f.debug_struct("UnixDiagAttrs");
598 for attr in self.clone() {
599 let attr = match attr {
600 Ok(a) => a,
601 Err(err) => {
602 fmt.finish()?;
603 f.write_str("Err(")?;
604 err.fmt(f)?;
605 return f.write_str(")");
606 }
607 };
608 match attr {
609 UnixDiagAttrs::Name(val) => fmt.field("Name", &FormatBinStr(val)),
610 UnixDiagAttrs::Vfs(val) => fmt.field("Vfs", &val),
611 UnixDiagAttrs::Peer(val) => fmt.field("Peer", &val),
612 UnixDiagAttrs::Icons(val) => fmt.field("Icons", &val),
613 UnixDiagAttrs::Rqlen(val) => fmt.field("Rqlen", &val),
614 UnixDiagAttrs::Meminfo(val) => fmt.field("Meminfo", &val),
615 UnixDiagAttrs::Shutdown(val) => fmt.field("Shutdown", &val),
616 UnixDiagAttrs::Uid(val) => fmt.field("Uid", &val),
617 };
618 }
619 fmt.finish()
620 }
621}
622impl IterableUnixDiagAttrs<'_> {
623 pub fn lookup_attr(
624 &self,
625 offset: usize,
626 missing_type: Option<u16>,
627 ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
628 let mut stack = Vec::new();
629 let cur = ErrorContext::calc_offset(self.orig_loc, self.buf.as_ptr() as usize);
630 if missing_type.is_some() && cur == offset {
631 stack.push(("UnixDiagAttrs", offset));
632 return (
633 stack,
634 missing_type.and_then(|t| UnixDiagAttrs::attr_from_type(t)),
635 );
636 }
637 if cur > offset || cur + self.buf.len() < offset {
638 return (stack, None);
639 }
640 let mut attrs = self.clone();
641 let mut last_off = cur + attrs.pos;
642 while let Some(attr) = attrs.next() {
643 let Ok(attr) = attr else { break };
644 match attr {
645 UnixDiagAttrs::Name(val) => {
646 if last_off == offset {
647 stack.push(("Name", last_off));
648 break;
649 }
650 }
651 UnixDiagAttrs::Vfs(val) => {
652 if last_off == offset {
653 stack.push(("Vfs", last_off));
654 break;
655 }
656 }
657 UnixDiagAttrs::Peer(val) => {
658 if last_off == offset {
659 stack.push(("Peer", last_off));
660 break;
661 }
662 }
663 UnixDiagAttrs::Icons(val) => {
664 if last_off == offset {
665 stack.push(("Icons", last_off));
666 break;
667 }
668 }
669 UnixDiagAttrs::Rqlen(val) => {
670 if last_off == offset {
671 stack.push(("Rqlen", last_off));
672 break;
673 }
674 }
675 UnixDiagAttrs::Meminfo(val) => {
676 if last_off == offset {
677 stack.push(("Meminfo", last_off));
678 break;
679 }
680 }
681 UnixDiagAttrs::Shutdown(val) => {
682 if last_off == offset {
683 stack.push(("Shutdown", last_off));
684 break;
685 }
686 }
687 UnixDiagAttrs::Uid(val) => {
688 if last_off == offset {
689 stack.push(("Uid", last_off));
690 break;
691 }
692 }
693 _ => {}
694 };
695 last_off = cur + attrs.pos;
696 }
697 if !stack.is_empty() {
698 stack.push(("UnixDiagAttrs", cur));
699 }
700 (stack, None)
701 }
702}
703pub struct PushUnixDiagAttrs<Prev: Rec> {
704 pub(crate) prev: Option<Prev>,
705 pub(crate) header_offset: Option<usize>,
706}
707impl<Prev: Rec> Rec for PushUnixDiagAttrs<Prev> {
708 fn as_rec_mut(&mut self) -> &mut Vec<u8> {
709 self.prev.as_mut().unwrap().as_rec_mut()
710 }
711 fn as_rec(&self) -> &Vec<u8> {
712 self.prev.as_ref().unwrap().as_rec()
713 }
714}
715impl<Prev: Rec> PushUnixDiagAttrs<Prev> {
716 pub fn new(prev: Prev) -> Self {
717 Self {
718 prev: Some(prev),
719 header_offset: None,
720 }
721 }
722 pub fn end_nested(mut self) -> Prev {
723 let mut prev = self.prev.take().unwrap();
724 if let Some(header_offset) = &self.header_offset {
725 finalize_nested_header(prev.as_rec_mut(), *header_offset);
726 }
727 prev
728 }
729 #[doc = "Unix socket sun\\_path\\. May or may not contain '\\\\0'\\."]
730 pub fn push_name(mut self, value: &[u8]) -> Self {
731 push_header(self.as_rec_mut(), 0u16, value.len() as u16);
732 self.as_rec_mut().extend(value);
733 self
734 }
735 pub fn push_vfs(mut self, value: Vfs) -> Self {
736 push_header(self.as_rec_mut(), 1u16, value.as_slice().len() as u16);
737 self.as_rec_mut().extend(value.as_slice());
738 self
739 }
740 pub fn push_peer(mut self, value: u32) -> Self {
741 push_header(self.as_rec_mut(), 2u16, 4 as u16);
742 self.as_rec_mut().extend(value.to_ne_bytes());
743 self
744 }
745 pub fn push_icons(mut self, value: &[u8]) -> Self {
746 push_header(self.as_rec_mut(), 3u16, value.len() as u16);
747 self.as_rec_mut().extend(value);
748 self
749 }
750 pub fn push_rqlen(mut self, value: Rqlen) -> Self {
751 push_header(self.as_rec_mut(), 4u16, value.as_slice().len() as u16);
752 self.as_rec_mut().extend(value.as_slice());
753 self
754 }
755 pub fn push_meminfo(mut self, value: &[u8]) -> Self {
756 push_header(self.as_rec_mut(), 5u16, value.len() as u16);
757 self.as_rec_mut().extend(value);
758 self
759 }
760 pub fn push_shutdown(mut self, value: u8) -> Self {
761 push_header(self.as_rec_mut(), 6u16, 1 as u16);
762 self.as_rec_mut().extend(value.to_ne_bytes());
763 self
764 }
765 pub fn push_uid(mut self, value: u32) -> Self {
766 push_header(self.as_rec_mut(), 7u16, 4 as u16);
767 self.as_rec_mut().extend(value.to_ne_bytes());
768 self
769 }
770}
771impl<Prev: Rec> Drop for PushUnixDiagAttrs<Prev> {
772 fn drop(&mut self) {
773 if let Some(prev) = &mut self.prev {
774 if let Some(header_offset) = &self.header_offset {
775 finalize_nested_header(prev.as_rec_mut(), *header_offset);
776 }
777 }
778 }
779}
780#[doc = ""]
781#[derive(Debug)]
782pub struct OpUnixDiagDump<'r> {
783 request: Request<'r>,
784}
785impl<'r> OpUnixDiagDump<'r> {
786 pub fn new(mut request: Request<'r>, header: &Req) -> Self {
787 Self::write_header(request.buf_mut(), header);
788 Self {
789 request: request.set_dump(),
790 }
791 }
792 pub fn encode_request<'buf>(
793 buf: &'buf mut Vec<u8>,
794 header: &Req,
795 ) -> PushUnixDiagAttrs<&'buf mut Vec<u8>> {
796 Self::write_header(buf, header);
797 PushUnixDiagAttrs::new(buf)
798 }
799 pub fn encode(&mut self) -> PushUnixDiagAttrs<&mut Vec<u8>> {
800 PushUnixDiagAttrs::new(self.request.buf_mut())
801 }
802 pub fn into_encoder(self) -> PushUnixDiagAttrs<RequestBuf<'r>> {
803 PushUnixDiagAttrs::new(self.request.buf)
804 }
805 pub fn decode_request<'a>(buf: &'a [u8]) -> (Req, IterableUnixDiagAttrs<'a>) {
806 let (header, attrs) = buf.split_at(buf.len().min(Req::len()));
807 (
808 Req::new_from_slice(header).unwrap_or_default(),
809 IterableUnixDiagAttrs::with_loc(attrs, buf.as_ptr() as usize),
810 )
811 }
812 fn decode_reply<'a>(buf: &'a [u8]) -> (Msg, IterableUnixDiagAttrs<'a>) {
813 let (header, attrs) = buf.split_at(buf.len().min(Msg::len()));
814 (
815 Msg::new_from_slice(header).unwrap_or_default(),
816 IterableUnixDiagAttrs::with_loc(attrs, buf.as_ptr() as usize),
817 )
818 }
819 fn write_header<Prev: Rec>(prev: &mut Prev, header: &Req) {
820 prev.as_rec_mut().extend(header.as_slice());
821 }
822}
823impl NetlinkRequest for OpUnixDiagDump<'_> {
824 fn protocol(&self) -> Protocol {
825 Protocol::Raw {
826 protonum: 4u16,
827 request_type: 20u16,
828 }
829 }
830 fn flags(&self) -> u16 {
831 self.request.flags
832 }
833 fn payload(&self) -> &[u8] {
834 self.request.buf()
835 }
836 type ReplyType<'buf> = (Msg, IterableUnixDiagAttrs<'buf>);
837 fn decode_reply<'buf>(buf: &'buf [u8]) -> Self::ReplyType<'buf> {
838 Self::decode_reply(buf)
839 }
840 fn lookup(
841 buf: &[u8],
842 offset: usize,
843 missing_type: Option<u16>,
844 ) -> (Vec<(&'static str, usize)>, Option<&'static str>) {
845 Self::decode_request(buf)
846 .1
847 .lookup_attr(offset, missing_type)
848 }
849}
850#[derive(Debug)]
851pub struct ChainedFinal<'a> {
852 inner: Chained<'a>,
853}
854#[derive(Debug)]
855pub struct Chained<'a> {
856 buf: RequestBuf<'a>,
857 first_seq: u32,
858 lookups: Vec<(&'static str, LookupFn)>,
859 last_header_offset: usize,
860 last_kind: Option<RequestInfo>,
861}
862impl<'a> ChainedFinal<'a> {
863 pub fn into_chained(self) -> Chained<'a> {
864 self.inner
865 }
866 pub fn buf(&self) -> &Vec<u8> {
867 self.inner.buf()
868 }
869 pub fn buf_mut(&mut self) -> &mut Vec<u8> {
870 self.inner.buf_mut()
871 }
872 fn get_index(&self, seq: u32) -> Option<u32> {
873 let min = self.inner.first_seq;
874 let max = min.wrapping_add(self.inner.lookups.len() as u32);
875 return if min <= max {
876 (min..max).contains(&seq).then(|| seq - min)
877 } else if min <= seq {
878 Some(seq - min)
879 } else if seq < max {
880 Some(u32::MAX - min + seq)
881 } else {
882 None
883 };
884 }
885}
886impl crate::traits::NetlinkChained for ChainedFinal<'_> {
887 fn protonum(&self) -> u16 {
888 PROTONUM
889 }
890 fn payload(&self) -> &[u8] {
891 self.buf()
892 }
893 fn chain_len(&self) -> usize {
894 self.inner.lookups.len()
895 }
896 fn get_index(&self, seq: u32) -> Option<usize> {
897 self.get_index(seq).map(|n| n as usize)
898 }
899 fn name(&self, index: usize) -> &'static str {
900 self.inner.lookups[index].0
901 }
902 fn lookup(&self, index: usize) -> LookupFn {
903 self.inner.lookups[index].1
904 }
905}
906impl Chained<'static> {
907 pub fn new(first_seq: u32) -> Self {
908 Self::new_from_buf(Vec::new(), first_seq)
909 }
910 pub fn new_from_buf(buf: Vec<u8>, first_seq: u32) -> Self {
911 Self {
912 buf: RequestBuf::Own(buf),
913 first_seq,
914 lookups: Vec::new(),
915 last_header_offset: 0,
916 last_kind: None,
917 }
918 }
919 pub fn into_buf(self) -> Vec<u8> {
920 match self.buf {
921 RequestBuf::Own(buf) => buf,
922 _ => unreachable!(),
923 }
924 }
925}
926impl<'a> Chained<'a> {
927 pub fn new_with_buf(buf: &'a mut Vec<u8>, first_seq: u32) -> Self {
928 Self {
929 buf: RequestBuf::Ref(buf),
930 first_seq,
931 lookups: Vec::new(),
932 last_header_offset: 0,
933 last_kind: None,
934 }
935 }
936 pub fn finalize(mut self) -> ChainedFinal<'a> {
937 self.update_header();
938 ChainedFinal { inner: self }
939 }
940 pub fn request(&mut self) -> Request<'_> {
941 self.update_header();
942 self.last_header_offset = self.buf().len();
943 self.buf_mut().extend_from_slice(Nlmsghdr::new().as_slice());
944 let mut request = Request::new_extend(self.buf.buf_mut());
945 self.last_kind = None;
946 request.writeback = Some(&mut self.last_kind);
947 request
948 }
949 pub fn buf(&self) -> &Vec<u8> {
950 self.buf.buf()
951 }
952 pub fn buf_mut(&mut self) -> &mut Vec<u8> {
953 self.buf.buf_mut()
954 }
955 fn update_header(&mut self) {
956 let Some(RequestInfo {
957 protocol,
958 flags,
959 name,
960 lookup,
961 }) = self.last_kind
962 else {
963 if !self.buf().is_empty() {
964 assert_eq!(self.last_header_offset + Nlmsghdr::len(), self.buf().len());
965 self.buf.buf_mut().truncate(self.last_header_offset);
966 }
967 return;
968 };
969 let header_offset = self.last_header_offset;
970 let request_type = match protocol {
971 Protocol::Raw { request_type, .. } => request_type,
972 Protocol::Generic(_) => unreachable!(),
973 };
974 let index = self.lookups.len();
975 let seq = self.first_seq.wrapping_add(index as u32);
976 self.lookups.push((name, lookup));
977 let buf = self.buf_mut();
978 align(buf);
979 let header = Nlmsghdr {
980 len: (buf.len() - header_offset) as u32,
981 r#type: request_type,
982 flags: flags | consts::NLM_F_REQUEST as u16 | consts::NLM_F_ACK as u16,
983 seq,
984 pid: 0,
985 };
986 buf[header_offset..(header_offset + 16)].clone_from_slice(header.as_slice());
987 }
988}
989use crate::traits::LookupFn;
990use crate::utils::RequestBuf;
991#[derive(Debug)]
992pub struct Request<'buf> {
993 buf: RequestBuf<'buf>,
994 flags: u16,
995 writeback: Option<&'buf mut Option<RequestInfo>>,
996}
997#[allow(unused)]
998#[derive(Debug, Clone)]
999pub struct RequestInfo {
1000 protocol: Protocol,
1001 flags: u16,
1002 name: &'static str,
1003 lookup: LookupFn,
1004}
1005impl Request<'static> {
1006 pub fn new() -> Self {
1007 Self::new_from_buf(Vec::new())
1008 }
1009 pub fn new_from_buf(buf: Vec<u8>) -> Self {
1010 Self {
1011 flags: 0,
1012 buf: RequestBuf::Own(buf),
1013 writeback: None,
1014 }
1015 }
1016 pub fn into_buf(self) -> Vec<u8> {
1017 match self.buf {
1018 RequestBuf::Own(buf) => buf,
1019 _ => unreachable!(),
1020 }
1021 }
1022}
1023impl<'buf> Request<'buf> {
1024 pub fn new_with_buf(buf: &'buf mut Vec<u8>) -> Self {
1025 buf.clear();
1026 Self::new_extend(buf)
1027 }
1028 pub fn new_extend(buf: &'buf mut Vec<u8>) -> Self {
1029 Self {
1030 flags: 0,
1031 buf: RequestBuf::Ref(buf),
1032 writeback: None,
1033 }
1034 }
1035 fn do_writeback(&mut self, protocol: Protocol, name: &'static str, lookup: LookupFn) {
1036 let Some(writeback) = &mut self.writeback else {
1037 return;
1038 };
1039 **writeback = Some(RequestInfo {
1040 protocol,
1041 flags: self.flags,
1042 name,
1043 lookup,
1044 })
1045 }
1046 pub fn buf(&self) -> &Vec<u8> {
1047 self.buf.buf()
1048 }
1049 pub fn buf_mut(&mut self) -> &mut Vec<u8> {
1050 self.buf.buf_mut()
1051 }
1052 #[doc = "Set `NLM_F_CREATE` flag"]
1053 pub fn set_create(mut self) -> Self {
1054 self.flags |= consts::NLM_F_CREATE as u16;
1055 self
1056 }
1057 #[doc = "Set `NLM_F_EXCL` flag"]
1058 pub fn set_excl(mut self) -> Self {
1059 self.flags |= consts::NLM_F_EXCL as u16;
1060 self
1061 }
1062 #[doc = "Set `NLM_F_REPLACE` flag"]
1063 pub fn set_replace(mut self) -> Self {
1064 self.flags |= consts::NLM_F_REPLACE as u16;
1065 self
1066 }
1067 #[doc = "Set `NLM_F_CREATE` and `NLM_F_REPLACE` flag"]
1068 pub fn set_change(self) -> Self {
1069 self.set_create().set_replace()
1070 }
1071 #[doc = "Set `NLM_F_APPEND` flag"]
1072 pub fn set_append(mut self) -> Self {
1073 self.flags |= consts::NLM_F_APPEND as u16;
1074 self
1075 }
1076 #[doc = "Set `self.flags |= flags`"]
1077 pub fn set_flags(mut self, flags: u16) -> Self {
1078 self.flags |= flags;
1079 self
1080 }
1081 #[doc = "Set `self.flags ^= self.flags & flags`"]
1082 pub fn unset_flags(mut self, flags: u16) -> Self {
1083 self.flags ^= self.flags & flags;
1084 self
1085 }
1086 #[doc = "Set `NLM_F_DUMP` flag"]
1087 fn set_dump(mut self) -> Self {
1088 self.flags |= consts::NLM_F_DUMP as u16;
1089 self
1090 }
1091 #[doc = ""]
1092 pub fn op_unix_diag_dump(self, header: &Req) -> OpUnixDiagDump<'buf> {
1093 let mut res = OpUnixDiagDump::new(self, header);
1094 res.request
1095 .do_writeback(res.protocol(), "op-unix-diag-dump", OpUnixDiagDump::lookup);
1096 res
1097 }
1098}