netlink_packet_route/address/
attribute.rs1use 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
24const IPV4_ADDR_LEN: usize = 4;
26const 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 Broadcast(Ipv4Addr),
37 Anycast(Ipv6Addr),
39 CacheInfo(CacheInfo),
40 Multicast(Ipv6Addr),
42 Flags(AddressFlags),
43 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}