netlink_packet_sock_diag/inet/
socket_id.rs

1// SPDX-License-Identifier: MIT
2
3use std::convert::{TryFrom, TryInto};
4use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
5
6use byteorder::{BigEndian, ByteOrder};
7use netlink_packet_utils::traits::{Emitable, ParseableParametrized};
8use netlink_packet_utils::{DecodeError, buffer};
9
10use crate::constants::*;
11
12pub const SOCKET_ID_LEN: usize = 48;
13
14buffer!(SocketIdBuffer(SOCKET_ID_LEN) {
15    source_port: (slice, 0..2),
16    destination_port: (slice, 2..4),
17    source_address: (slice, 4..20),
18    destination_address: (slice, 20..36),
19    interface_id: (u32, 36..40),
20    cookie: (slice, 40..48),
21});
22
23#[derive(Debug, PartialEq, Eq, Clone)]
24pub struct SocketId {
25    pub source_port: u16,
26    pub destination_port: u16,
27    pub source_address: IpAddr,
28    pub destination_address: IpAddr,
29    pub interface_id: u32,
30    /// An array of opaque identifiers that could be used along with
31    /// other fields of this structure to specify an individual
32    /// socket. It is ignored when querying for a list of sockets, as
33    /// well as when all its elements are set to `0xff`.
34    pub cookie: [u8; 8],
35}
36
37impl SocketId {
38    pub fn new_v4() -> Self {
39        Self {
40            source_port: 0,
41            destination_port: 0,
42            source_address: IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
43            destination_address: IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
44            interface_id: 0,
45            cookie: [0; 8],
46        }
47    }
48    pub fn new_v6() -> Self {
49        Self {
50            source_port: 0,
51            destination_port: 0,
52            source_address: IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)),
53            destination_address: IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)),
54            interface_id: 0,
55            cookie: [0; 8],
56        }
57    }
58}
59
60impl<'a, T: AsRef<[u8]> + 'a> ParseableParametrized<SocketIdBuffer<&'a T>, u8> for SocketId {
61    type Error = DecodeError;
62    fn parse_with_param(buf: &SocketIdBuffer<&'a T>, af: u8) -> Result<Self, DecodeError> {
63        let (source_address, destination_address) = match af {
64            AF_INET => {
65                let s = &buf.source_address()[..4];
66                let source = IpAddr::V4(Ipv4Addr::new(s[0], s[1], s[2], s[3]));
67
68                let s = &buf.destination_address()[..4];
69                let destination = IpAddr::V4(Ipv4Addr::new(s[0], s[1], s[2], s[3]));
70
71                (source, destination)
72            }
73            AF_INET6 => {
74                let bytes: [u8; 16] = buf.source_address().try_into().unwrap();
75                let source = IpAddr::V6(Ipv6Addr::from(bytes));
76
77                let bytes: [u8; 16] = buf.destination_address().try_into().unwrap();
78                let destination = IpAddr::V6(Ipv6Addr::from(bytes));
79                (source, destination)
80            }
81            _ => {
82                return Err(DecodeError::from(format!(
83                    "unsupported address family {af}: expected AF_INET ({AF_INET}) or AF_INET6 ({AF_INET6})"
84                )));
85            }
86        };
87
88        Ok(Self {
89            source_port: BigEndian::read_u16(buf.source_port()),
90            destination_port: BigEndian::read_u16(buf.destination_port()),
91            source_address,
92            destination_address,
93            interface_id: buf.interface_id(),
94            // Unwrapping is safe because SocketIdBuffer::cookie()
95            // returns a slice of exactly 8 bytes.
96            cookie: TryFrom::try_from(buf.cookie()).unwrap(),
97        })
98    }
99}
100
101impl Emitable for SocketId {
102    fn buffer_len(&self) -> usize {
103        SOCKET_ID_LEN
104    }
105
106    fn emit(&self, buffer: &mut [u8]) {
107        let mut buffer = SocketIdBuffer::new_unchecked(buffer);
108
109        BigEndian::write_u16(buffer.source_port_mut(), self.source_port);
110        BigEndian::write_u16(buffer.destination_port_mut(), self.destination_port);
111
112        let mut address_buf: [u8; 16] = [0; 16];
113        match self.source_address {
114            IpAddr::V4(ip) => address_buf[0..4].copy_from_slice(&ip.octets()[..]),
115            IpAddr::V6(ip) => address_buf.copy_from_slice(&ip.octets()[..]),
116        }
117
118        buffer.source_address_mut().copy_from_slice(&address_buf[..]);
119
120        address_buf = [0; 16];
121        match self.destination_address {
122            IpAddr::V4(ip) => address_buf[0..4].copy_from_slice(&ip.octets()[..]),
123            IpAddr::V6(ip) => address_buf.copy_from_slice(&ip.octets()[..]),
124        }
125
126        buffer.destination_address_mut().copy_from_slice(&address_buf[..]);
127
128        buffer.set_interface_id(self.interface_id);
129        buffer.cookie_mut().copy_from_slice(&self.cookie[..]);
130    }
131}