netlink_packet_sock_diag/unix/
response.rs

1// SPDX-License-Identifier: MIT
2
3use std::convert::TryFrom;
4
5use anyhow::Context;
6use netlink_packet_utils::nla::{NlaBuffer, NlasIterator};
7use netlink_packet_utils::traits::{Emitable, Parseable};
8use netlink_packet_utils::{DecodeError, buffer};
9use smallvec::SmallVec;
10
11use crate::constants::*;
12use crate::unix::nlas::{MemInfo, Nla};
13
14pub const UNIX_RESPONSE_HEADER_LEN: usize = 16;
15
16buffer!(UnixResponseBuffer(UNIX_RESPONSE_HEADER_LEN) {
17    family: (u8, 0),
18    kind: (u8, 1),
19    state: (u8, 2),
20    pad: (u8, 3),
21    inode: (u32, 4..8),
22    cookie: (slice, 8..UNIX_RESPONSE_HEADER_LEN),
23    payload: (slice, UNIX_RESPONSE_HEADER_LEN..),
24});
25
26/// The response to a query for IPv4 or IPv6 sockets
27#[derive(Debug, PartialEq, Eq, Clone)]
28pub struct UnixResponseHeader {
29    /// One of `SOCK_PACKET`, `SOCK_STREAM`, or `SOCK_SEQPACKET`
30    pub kind: u8,
31    /// State of the socket. According to `man 7 sock_diag` it can be
32    /// either `TCP_ESTABLISHED` or `TCP_LISTEN`. However datagram
33    /// UNIX sockets are not connection oriented so I would assume
34    /// that this field can also take other value (maybe `0`) for
35    /// these sockets.
36    pub state: u8,
37    /// Socket inode number.
38    pub inode: u32,
39    pub cookie: [u8; 8],
40}
41
42impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<UnixResponseBuffer<&'a T>> for UnixResponseHeader {
43    type Error = DecodeError;
44    fn parse(buf: &UnixResponseBuffer<&'a T>) -> Result<Self, DecodeError> {
45        Ok(Self {
46            kind: buf.kind(),
47            state: buf.state(),
48            inode: buf.inode(),
49            // Unwrapping is safe because UnixResponseBuffer::cookie()
50            // returns a slice of exactly 8 bytes.
51            cookie: TryFrom::try_from(buf.cookie()).unwrap(),
52        })
53    }
54}
55
56impl Emitable for UnixResponseHeader {
57    fn buffer_len(&self) -> usize {
58        UNIX_RESPONSE_HEADER_LEN
59    }
60
61    fn emit(&self, buf: &mut [u8]) {
62        let mut buf = UnixResponseBuffer::new_unchecked(buf);
63        buf.set_family(AF_UNIX);
64        buf.set_kind(self.kind);
65        buf.set_state(self.state);
66        buf.set_pad(0);
67        buf.set_inode(self.inode);
68        buf.cookie_mut().copy_from_slice(&self.cookie[..]);
69    }
70}
71
72#[derive(Debug, PartialEq, Eq, Clone)]
73pub struct UnixResponse {
74    pub header: UnixResponseHeader,
75    pub nlas: SmallVec<[Nla; 8]>,
76}
77
78impl UnixResponse {
79    pub fn peer(&self) -> Option<u32> {
80        self.nlas.iter().find_map(
81            |nla| {
82                if let Nla::Peer(inode) = nla { Some(*inode) } else { None }
83            },
84        )
85    }
86
87    pub fn name(&self) -> Option<&String> {
88        self.nlas.iter().find_map(|nla| if let Nla::Name(name) = nla { Some(name) } else { None })
89    }
90
91    pub fn pending_connections(&self) -> Option<&[u32]> {
92        self.nlas.iter().find_map(|nla| {
93            if let Nla::PendingConnections(connections) = nla {
94                Some(&connections[..])
95            } else {
96                None
97            }
98        })
99    }
100
101    fn mem_info(&self) -> Option<MemInfo> {
102        self.nlas
103            .iter()
104            .find_map(|nla| if let Nla::MemInfo(mem_info) = nla { Some(*mem_info) } else { None })
105    }
106
107    pub fn shutdown_state(&self) -> Option<u8> {
108        self.nlas.iter().find_map(|nla| {
109            if let Nla::Shutdown(shutdown_state) = nla { Some(*shutdown_state) } else { None }
110        })
111    }
112
113    fn receive_queue_length(&self) -> Option<(u32, u32)> {
114        self.nlas.iter().find_map(|nla| {
115            if let Nla::ReceiveQueueLength(x, y) = nla { Some((*x, *y)) } else { None }
116        })
117    }
118
119    pub fn number_of_pending_connection(&self) -> Option<u32> {
120        if self.header.state == TCP_LISTEN {
121            self.receive_queue_length().map(|(n, _)| n)
122        } else {
123            None
124        }
125    }
126
127    pub fn max_number_of_pending_connection(&self) -> Option<u32> {
128        if self.header.state == TCP_LISTEN {
129            self.receive_queue_length().map(|(_, n)| n)
130        } else {
131            None
132        }
133    }
134
135    pub fn receive_queue_size(&self) -> Option<u32> {
136        if self.header.state == TCP_LISTEN {
137            None
138        } else {
139            self.receive_queue_length().map(|(n, _)| n)
140        }
141    }
142
143    pub fn send_queue_size(&self) -> Option<u32> {
144        if self.header.state == TCP_LISTEN {
145            self.receive_queue_length().map(|(n, _)| n)
146        } else {
147            None
148        }
149    }
150
151    pub fn max_datagram_size(&self) -> Option<u32> {
152        self.mem_info().map(|mem_info| mem_info.max_datagram_size)
153    }
154
155    pub fn memory_used_for_outgoing_data(&self) -> Option<u32> {
156        self.mem_info().map(|mem_info| mem_info.alloc)
157    }
158}
159
160impl<'a, T: AsRef<[u8]> + ?Sized> UnixResponseBuffer<&'a T> {
161    pub fn nlas(&self) -> impl Iterator<Item = Result<NlaBuffer<&'a [u8]>, DecodeError>> {
162        NlasIterator::new(self.payload()).map(|nla| nla.map_err(Into::into))
163    }
164}
165
166impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<UnixResponseBuffer<&'a T>> for SmallVec<[Nla; 8]> {
167    type Error = DecodeError;
168    fn parse(buf: &UnixResponseBuffer<&'a T>) -> Result<Self, DecodeError> {
169        let mut nlas = smallvec![];
170        for nla_buf in buf.nlas() {
171            nlas.push(Nla::parse(&nla_buf?)?);
172        }
173        Ok(nlas)
174    }
175}
176
177impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<UnixResponseBuffer<&'a T>> for UnixResponse {
178    type Error = DecodeError;
179    fn parse(buf: &UnixResponseBuffer<&'a T>) -> Result<Self, DecodeError> {
180        let header =
181            UnixResponseHeader::parse(buf).context("failed to parse inet response header")?;
182        let nlas =
183            SmallVec::<[Nla; 8]>::parse(buf).context("failed to parse inet response NLAs")?;
184        Ok(UnixResponse { header, nlas })
185    }
186}
187
188impl Emitable for UnixResponse {
189    fn buffer_len(&self) -> usize {
190        self.header.buffer_len() + self.nlas.as_slice().buffer_len()
191    }
192
193    fn emit(&self, buffer: &mut [u8]) {
194        self.header.emit(buffer);
195        self.nlas.as_slice().emit(&mut buffer[self.header.buffer_len()..]);
196    }
197}