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