netlink_packet_route/address/
attribute.rs

1// SPDX-License-Identifier: MIT
2
3use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
4
5use netlink_packet_core::{
6    emit_i32, emit_u32, parse_i32, parse_string, parse_u32, parse_u8,
7    DecodeError, DefaultNla, Emitable, ErrorContext, Nla, NlaBuffer, Parseable,
8};
9
10use crate::address::{AddressFlags, CacheInfo, CacheInfoBuffer};
11
12const IFA_ADDRESS: u16 = 1;
13const IFA_LOCAL: u16 = 2;
14const IFA_LABEL: u16 = 3;
15const IFA_BROADCAST: u16 = 4;
16const IFA_ANYCAST: u16 = 5;
17const IFA_CACHEINFO: u16 = 6;
18const IFA_MULTICAST: u16 = 7;
19const IFA_FLAGS: u16 = 8;
20const IFA_RT_PRIORITY: u16 = 9;
21const IFA_TARGET_NETNSID: u16 = 10;
22const IFA_PROTO: u16 = 11;
23
24// 32 bites
25const IPV4_ADDR_LEN: usize = 4;
26// 128 bites
27const IPV6_ADDR_LEN: usize = 16;
28
29#[derive(Debug, PartialEq, Eq, Clone)]
30#[non_exhaustive]
31pub enum AddressAttribute {
32    Address(IpAddr),
33    Local(IpAddr),
34    Label(String),
35    /// IPv4 only
36    Broadcast(Ipv4Addr),
37    /// IPv6 only
38    Anycast(Ipv6Addr),
39    CacheInfo(CacheInfo),
40    /// IPv6 only
41    Multicast(Ipv6Addr),
42    Flags(AddressFlags),
43    /// priority/metric for prefix route
44    RoutePriority(u32),
45    TargetNetNsId(i32),
46    Protocol(AddressProtocol),
47    Other(DefaultNla),
48}
49
50impl Nla for AddressAttribute {
51    fn value_len(&self) -> usize {
52        match *self {
53            Self::Broadcast(_) => IPV4_ADDR_LEN,
54            Self::Anycast(_) | Self::Multicast(_) => IPV6_ADDR_LEN,
55            Self::Address(ref addr) | Self::Local(ref addr) => {
56                if addr.is_ipv6() {
57                    IPV6_ADDR_LEN
58                } else {
59                    IPV4_ADDR_LEN
60                }
61            }
62            Self::Label(ref string) => string.len() + 1,
63            Self::Flags(_)
64            | Self::RoutePriority(_)
65            | Self::TargetNetNsId(_) => 4,
66            Self::CacheInfo(ref attr) => attr.buffer_len(),
67            Self::Protocol(_) => 1,
68            Self::Other(ref attr) => attr.value_len(),
69        }
70    }
71
72    fn emit_value(&self, buffer: &mut [u8]) {
73        match self {
74            Self::Broadcast(ref addr) => buffer.copy_from_slice(&addr.octets()),
75            Self::Anycast(ref addr) | Self::Multicast(ref addr) => {
76                buffer.copy_from_slice(&addr.octets())
77            }
78            Self::Address(ref addr) | Self::Local(ref addr) => match addr {
79                IpAddr::V4(addr4) => buffer.copy_from_slice(&addr4.octets()),
80                IpAddr::V6(addr6) => buffer.copy_from_slice(&addr6.octets()),
81            },
82            Self::Label(ref string) => {
83                buffer[..string.len()].copy_from_slice(string.as_bytes());
84                buffer[string.len()] = 0;
85            }
86            Self::Flags(ref value) => emit_u32(buffer, value.bits()).unwrap(),
87            Self::CacheInfo(ref attr) => attr.emit(buffer),
88            Self::RoutePriority(v) => emit_u32(buffer, *v).unwrap(),
89            Self::TargetNetNsId(v) => emit_i32(buffer, *v).unwrap(),
90            Self::Protocol(v) => buffer[0] = u8::from(*v),
91            Self::Other(ref attr) => attr.emit_value(buffer),
92        }
93    }
94
95    fn kind(&self) -> u16 {
96        match *self {
97            Self::Address(_) => IFA_ADDRESS,
98            Self::Local(_) => IFA_LOCAL,
99            Self::Label(_) => IFA_LABEL,
100            Self::Broadcast(_) => IFA_BROADCAST,
101            Self::Anycast(_) => IFA_ANYCAST,
102            Self::CacheInfo(_) => IFA_CACHEINFO,
103            Self::Multicast(_) => IFA_MULTICAST,
104            Self::Flags(_) => IFA_FLAGS,
105            Self::RoutePriority(_) => IFA_RT_PRIORITY,
106            Self::TargetNetNsId(_) => IFA_TARGET_NETNSID,
107            Self::Protocol(_) => IFA_PROTO,
108            Self::Other(ref nla) => nla.kind(),
109        }
110    }
111}
112
113impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
114    for AddressAttribute
115{
116    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
117        let payload = buf.value();
118        Ok(match buf.kind() {
119            IFA_ADDRESS => {
120                if payload.len() == IPV4_ADDR_LEN {
121                    let mut data = [0u8; IPV4_ADDR_LEN];
122                    data.copy_from_slice(&payload[0..IPV4_ADDR_LEN]);
123                    Self::Address(IpAddr::from(data))
124                } else if payload.len() == IPV6_ADDR_LEN {
125                    let mut data = [0u8; IPV6_ADDR_LEN];
126                    data.copy_from_slice(&payload[0..IPV6_ADDR_LEN]);
127                    Self::Address(IpAddr::from(data))
128                } else {
129                    return Err(DecodeError::from(format!(
130                        "Invalid IFA_LOCAL, got unexpected length of payload \
131                         {payload:?}"
132                    )));
133                }
134            }
135            IFA_LOCAL => {
136                if payload.len() == IPV4_ADDR_LEN {
137                    let mut data = [0u8; IPV4_ADDR_LEN];
138                    data.copy_from_slice(&payload[0..IPV4_ADDR_LEN]);
139                    Self::Local(IpAddr::from(data))
140                } else if payload.len() == IPV6_ADDR_LEN {
141                    let mut data = [0u8; IPV6_ADDR_LEN];
142                    data.copy_from_slice(&payload[0..IPV6_ADDR_LEN]);
143                    Self::Local(IpAddr::from(data))
144                } else {
145                    return Err(DecodeError::from(format!(
146                        "Invalid IFA_LOCAL, got unexpected length of payload \
147                         {payload:?}"
148                    )));
149                }
150            }
151            IFA_LABEL => Self::Label(
152                parse_string(payload).context("invalid IFA_LABEL value")?,
153            ),
154            IFA_BROADCAST => {
155                if payload.len() == IPV4_ADDR_LEN {
156                    let mut data = [0u8; IPV4_ADDR_LEN];
157                    data.copy_from_slice(&payload[0..IPV4_ADDR_LEN]);
158                    Self::Broadcast(Ipv4Addr::from(data))
159                } else {
160                    return Err(DecodeError::from(format!(
161                        "Invalid IFA_BROADCAST, got unexpected length of IPv4 \
162                         address payload {payload:?}"
163                    )));
164                }
165            }
166            IFA_ANYCAST => {
167                if payload.len() == IPV6_ADDR_LEN {
168                    let mut data = [0u8; IPV6_ADDR_LEN];
169                    data.copy_from_slice(&payload[0..IPV6_ADDR_LEN]);
170                    Self::Anycast(Ipv6Addr::from(data))
171                } else {
172                    return Err(DecodeError::from(format!(
173                        "Invalid IFA_ANYCAST, got unexpected length of IPv6 \
174                         address payload {payload:?}"
175                    )));
176                }
177            }
178            IFA_CACHEINFO => Self::CacheInfo(
179                CacheInfo::parse(&CacheInfoBuffer::new(payload))
180                    .context(format!("Invalid IFA_CACHEINFO {payload:?}"))?,
181            ),
182            IFA_MULTICAST => {
183                if payload.len() == IPV6_ADDR_LEN {
184                    let mut data = [0u8; IPV6_ADDR_LEN];
185                    data.copy_from_slice(&payload[0..IPV6_ADDR_LEN]);
186                    Self::Multicast(Ipv6Addr::from(data))
187                } else {
188                    return Err(DecodeError::from(format!(
189                        "Invalid IFA_MULTICAST, got unexpected length of IPv6 \
190                         address payload {payload:?}"
191                    )));
192                }
193            }
194            IFA_FLAGS => Self::Flags(AddressFlags::from_bits_retain(
195                parse_u32(payload).context("invalid IFA_FLAGS value")?,
196            )),
197            IFA_RT_PRIORITY => Self::RoutePriority(
198                parse_u32(payload).context("invalid IFA_RT_PRIORITY value")?,
199            ),
200            IFA_TARGET_NETNSID => Self::TargetNetNsId(
201                parse_i32(payload)
202                    .context("invalid IFA_TARGET_NETNSID value")?,
203            ),
204            IFA_PROTO => Self::Protocol(
205                parse_u8(payload).context("invalid IFA_PROTO value")?.into(),
206            ),
207            kind => Self::Other(
208                DefaultNla::parse(buf)
209                    .context(format!("unknown NLA type {kind}"))?,
210            ),
211        })
212    }
213}
214
215const IFAPROT_KERNEL_LO: u8 = 1;
216const IFAPROT_KERNEL_RA: u8 = 2;
217const IFAPROT_KERNEL_LL: u8 = 3;
218
219#[derive(Debug, Clone, Copy, Eq, PartialEq)]
220#[non_exhaustive]
221pub enum AddressProtocol {
222    Loopback,
223    RouterAnnouncement,
224    LinkLocal,
225    Other(u8),
226}
227
228impl From<u8> for AddressProtocol {
229    fn from(d: u8) -> Self {
230        match d {
231            IFAPROT_KERNEL_LO => Self::Loopback,
232            IFAPROT_KERNEL_RA => Self::RouterAnnouncement,
233            IFAPROT_KERNEL_LL => Self::LinkLocal,
234            _ => Self::Other(d),
235        }
236    }
237}
238
239impl From<AddressProtocol> for u8 {
240    fn from(d: AddressProtocol) -> Self {
241        match d {
242            AddressProtocol::Loopback => IFAPROT_KERNEL_LO,
243            AddressProtocol::RouterAnnouncement => IFAPROT_KERNEL_RA,
244            AddressProtocol::LinkLocal => IFAPROT_KERNEL_LL,
245            AddressProtocol::Other(d) => d,
246        }
247    }
248}