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