netlink_packet_route/rule/
attribute.rs1use std::net::IpAddr;
4
5use netlink_packet_core::{
6 emit_u32, parse_string, parse_u32, parse_u8, DecodeError, DefaultNla,
7 Emitable, ErrorContext, Nla, NlaBuffer, Parseable,
8};
9
10use crate::{
11 ip::{emit_ip_addr, ip_addr_len, parse_ip_addr, IpProtocol},
12 route::{RouteProtocol, RouteRealm},
13 rule::{RulePortRange, RuleUidRange},
14};
15
16const FRA_DST: u16 = 1;
17const FRA_SRC: u16 = 2;
18const FRA_IIFNAME: u16 = 3;
19const FRA_GOTO: u16 = 4;
20const FRA_PRIORITY: u16 = 6;
22const FRA_FWMARK: u16 = 10;
26const FRA_FLOW: u16 = 11;
27const FRA_TUN_ID: u16 = 12;
28const FRA_SUPPRESS_IFGROUP: u16 = 13;
29const FRA_SUPPRESS_PREFIXLEN: u16 = 14;
30const FRA_TABLE: u16 = 15;
31const FRA_FWMASK: u16 = 16;
32const FRA_OIFNAME: u16 = 17;
33const FRA_L3MDEV: u16 = 19;
35const FRA_UID_RANGE: u16 = 20;
36const FRA_PROTOCOL: u16 = 21;
37const FRA_IP_PROTO: u16 = 22;
38const FRA_SPORT_RANGE: u16 = 23;
39const FRA_DPORT_RANGE: u16 = 24;
40
41#[derive(Debug, PartialEq, Eq, Clone)]
42#[non_exhaustive]
43pub enum RuleAttribute {
44 Destination(IpAddr),
46 Source(IpAddr),
48 Iifname(String),
50 Goto(u32),
52 Priority(u32),
53 FwMark(u32),
54 FwMask(u32),
55 Realm(RouteRealm),
57 TunId(u32),
58 SuppressIfGroup(u32),
59 SuppressPrefixLen(u32),
60 Table(u32),
61 Oifname(String),
63 L3MDev(bool),
64 UidRange(RuleUidRange),
65 Protocol(RouteProtocol),
66 IpProtocol(IpProtocol),
67 SourcePortRange(RulePortRange),
68 DestinationPortRange(RulePortRange),
69 Other(DefaultNla),
70}
71
72impl Nla for RuleAttribute {
73 fn value_len(&self) -> usize {
74 match self {
75 Self::Destination(ip) | Self::Source(ip) => ip_addr_len(ip),
76 Self::UidRange(v) => v.buffer_len(),
77 Self::SourcePortRange(v) | Self::DestinationPortRange(v) => {
78 v.buffer_len()
79 }
80 Self::Iifname(s) | Self::Oifname(s) => s.len() + 1,
81 Self::Priority(_)
82 | Self::FwMark(_)
83 | Self::FwMask(_)
84 | Self::TunId(_)
85 | Self::Goto(_)
86 | Self::SuppressIfGroup(_)
87 | Self::SuppressPrefixLen(_)
88 | Self::Table(_) => 4,
89 Self::Realm(v) => v.buffer_len(),
90 Self::L3MDev(_) | Self::Protocol(_) | Self::IpProtocol(_) => 1,
91 Self::Other(attr) => attr.value_len(),
92 }
93 }
94
95 fn kind(&self) -> u16 {
96 match self {
97 Self::Destination(_) => FRA_DST,
98 Self::Source(_) => FRA_SRC,
99 Self::Iifname(_) => FRA_IIFNAME,
100 Self::Goto(_) => FRA_GOTO,
101 Self::Priority(_) => FRA_PRIORITY,
102 Self::FwMark(_) => FRA_FWMARK,
103 Self::FwMask(_) => FRA_FWMASK,
104 Self::Realm(_) => FRA_FLOW,
105 Self::TunId(_) => FRA_TUN_ID,
106 Self::SuppressIfGroup(_) => FRA_SUPPRESS_IFGROUP,
107 Self::SuppressPrefixLen(_) => FRA_SUPPRESS_PREFIXLEN,
108 Self::Table(_) => FRA_TABLE,
109 Self::Oifname(_) => FRA_OIFNAME,
110 Self::L3MDev(_) => FRA_L3MDEV,
111 Self::UidRange(_) => FRA_UID_RANGE,
112 Self::Protocol(_) => FRA_PROTOCOL,
113 Self::IpProtocol(_) => FRA_IP_PROTO,
114 Self::SourcePortRange(_) => FRA_SPORT_RANGE,
115 Self::DestinationPortRange(_) => FRA_DPORT_RANGE,
116 Self::Other(attr) => attr.kind(),
117 }
118 }
119
120 fn emit_value(&self, buffer: &mut [u8]) {
121 match self {
122 Self::Destination(ip) | Self::Source(ip) => {
123 emit_ip_addr(ip, buffer)
124 }
125 Self::SourcePortRange(v) | Self::DestinationPortRange(v) => {
126 v.emit(buffer)
127 }
128 Self::UidRange(v) => v.emit(buffer),
129 Self::Iifname(s) | Self::Oifname(s) => {
130 buffer[..s.len()].copy_from_slice(s.as_bytes())
131 }
132 Self::Realm(v) => v.emit(buffer),
133 Self::Priority(value)
134 | Self::FwMark(value)
135 | Self::FwMask(value)
136 | Self::TunId(value)
137 | Self::Goto(value)
138 | Self::SuppressIfGroup(value)
139 | Self::SuppressPrefixLen(value)
140 | Self::Table(value) => emit_u32(buffer, *value).unwrap(),
141 Self::L3MDev(value) => buffer[0] = (*value).into(),
142 Self::IpProtocol(value) => buffer[0] = u8::from(*value),
143 Self::Protocol(value) => buffer[0] = u8::from(*value),
144 Self::Other(attr) => attr.emit_value(buffer),
145 }
146 }
147}
148
149impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
150 for RuleAttribute
151{
152 fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
153 let payload = buf.value();
154
155 Ok(match buf.kind() {
156 FRA_DST => Self::Destination(
157 parse_ip_addr(payload)
158 .context(format!("Invalid FRA_DST value {payload:?}"))?,
159 ),
160 FRA_SRC => Self::Source(
161 parse_ip_addr(payload)
162 .context(format!("Invalid FRA_SRC value {payload:?}"))?,
163 ),
164 FRA_IIFNAME => Self::Iifname(
165 parse_string(payload).context("invalid FRA_IIFNAME value")?,
166 ),
167 FRA_GOTO => Self::Goto(
168 parse_u32(payload).context("invalid FRA_GOTO value")?,
169 ),
170 FRA_PRIORITY => Self::Priority(
171 parse_u32(payload).context("invalid FRA_PRIORITY value")?,
172 ),
173 FRA_FWMARK => Self::FwMark(
174 parse_u32(payload).context("invalid FRA_FWMARK value")?,
175 ),
176 FRA_FLOW => Self::Realm(
177 RouteRealm::parse(payload).context("invalid FRA_FLOW value")?,
178 ),
179 FRA_TUN_ID => Self::TunId(
180 parse_u32(payload).context("invalid FRA_TUN_ID value")?,
181 ),
182 FRA_SUPPRESS_IFGROUP => Self::SuppressIfGroup(
183 parse_u32(payload)
184 .context("invalid FRA_SUPPRESS_IFGROUP value")?,
185 ),
186 FRA_SUPPRESS_PREFIXLEN => Self::SuppressPrefixLen(
187 parse_u32(payload)
188 .context("invalid FRA_SUPPRESS_PREFIXLEN value")?,
189 ),
190 FRA_TABLE => Self::Table(
191 parse_u32(payload).context("invalid FRA_TABLE value")?,
192 ),
193 FRA_FWMASK => Self::FwMask(
194 parse_u32(payload).context("invalid FRA_FWMASK value")?,
195 ),
196 FRA_OIFNAME => Self::Oifname(
197 parse_string(payload).context("invalid FRA_OIFNAME value")?,
198 ),
199 FRA_L3MDEV => Self::L3MDev(
200 parse_u8(payload).context("invalid FRA_L3MDEV value")? > 0,
201 ),
202 FRA_UID_RANGE => Self::UidRange(
203 RuleUidRange::parse(payload)
204 .context("invalid FRA_UID_RANGE value")?,
205 ),
206 FRA_PROTOCOL => Self::Protocol(
207 parse_u8(payload)
208 .context("invalid FRA_PROTOCOL value")?
209 .into(),
210 ),
211 FRA_IP_PROTO => Self::IpProtocol(IpProtocol::from(
212 parse_u8(payload).context("invalid FRA_IP_PROTO value")?,
213 )),
214 FRA_SPORT_RANGE => Self::SourcePortRange(
215 RulePortRange::parse(payload)
216 .context("invalid FRA_SPORT_RANGE value")?,
217 ),
218 FRA_DPORT_RANGE => Self::DestinationPortRange(
219 RulePortRange::parse(payload)
220 .context("invalid FRA_DPORT_RANGE value")?,
221 ),
222 _ => Self::Other(
223 DefaultNla::parse(buf).context("invalid NLA (unknown kind)")?,
224 ),
225 })
226 }
227}