netlink_packet_route/rtnl/rule/nlas/
mod.rs1use anyhow::Context;
4use netlink_packet_utils::{
5 byteorder::{ByteOrder, NativeEndian},
6 nla::{self, DefaultNla, NlaBuffer},
7 parsers::{parse_string, parse_u32, parse_u8},
8 DecodeError, Parseable,
9};
10
11use crate::{
12 FRA_DPORT_RANGE, FRA_DST, FRA_FLOW, FRA_FWMARK, FRA_FWMASK, FRA_GOTO,
13 FRA_IIFNAME, FRA_IP_PROTO, FRA_L3MDEV, FRA_OIFNAME, FRA_PAD, FRA_PRIORITY,
14 FRA_PROTOCOL, FRA_SPORT_RANGE, FRA_SRC, FRA_SUPPRESS_IFGROUP,
15 FRA_SUPPRESS_PREFIXLEN, FRA_TABLE, FRA_TUN_ID, FRA_UID_RANGE, FRA_UNSPEC,
16};
17
18#[derive(Debug, PartialEq, Eq, Clone)]
19#[non_exhaustive]
20pub enum Nla {
21 Unspec(Vec<u8>),
22 Destination(Vec<u8>),
24 Source(Vec<u8>),
26 Iifname(String),
28 Goto(u32),
30 Priority(u32),
31 FwMark(u32),
32 FwMask(u32),
33 Flow(u32),
35 TunId(u32),
36 SuppressIfGroup(u32),
37 SuppressPrefixLen(u32),
38 Table(u32),
39 OifName(String),
41 Pad(Vec<u8>),
42 L3MDev(u8),
44 UidRange(Vec<u8>),
45 Protocol(u8),
47 IpProto(u8),
49 SourcePortRange(Vec<u8>),
50 DestinationPortRange(Vec<u8>),
51 Other(DefaultNla),
52}
53
54impl nla::Nla for Nla {
55 fn value_len(&self) -> usize {
56 use self::Nla::*;
57 match self {
58 Unspec(ref bytes)
59 | Destination(ref bytes)
60 | Source(ref bytes)
61 | Pad(ref bytes)
62 | UidRange(ref bytes)
63 | SourcePortRange(ref bytes)
64 | DestinationPortRange(ref bytes) => bytes.len(),
65 Iifname(ref s) | OifName(ref s) => s.as_bytes().len() + 1,
66 Priority(_) | FwMark(_) | FwMask(_) | Flow(_) | TunId(_)
67 | Goto(_) | SuppressIfGroup(_) | SuppressPrefixLen(_)
68 | Table(_) => 4,
69 L3MDev(_) | Protocol(_) | IpProto(_) => 1,
70 Other(attr) => attr.value_len(),
71 }
72 }
73
74 fn kind(&self) -> u16 {
75 use self::Nla::*;
76 match self {
77 Unspec(_) => FRA_UNSPEC,
78 Destination(_) => FRA_DST,
79 Source(_) => FRA_SRC,
80 Iifname(_) => FRA_IIFNAME,
81 Goto(_) => FRA_GOTO,
82 Priority(_) => FRA_PRIORITY,
83 FwMark(_) => FRA_FWMARK,
84 FwMask(_) => FRA_FWMASK,
85 Flow(_) => FRA_FLOW,
86 TunId(_) => FRA_TUN_ID,
87 SuppressIfGroup(_) => FRA_SUPPRESS_IFGROUP,
88 SuppressPrefixLen(_) => FRA_SUPPRESS_PREFIXLEN,
89 Table(_) => FRA_TABLE,
90 OifName(_) => FRA_OIFNAME,
91 Pad(_) => FRA_PAD,
92 L3MDev(_) => FRA_L3MDEV,
93 UidRange(_) => FRA_UID_RANGE,
94 Protocol(_) => FRA_PROTOCOL,
95 IpProto(_) => FRA_IP_PROTO,
96 SourcePortRange(_) => FRA_SPORT_RANGE,
97 DestinationPortRange(_) => FRA_DPORT_RANGE,
98 Other(attr) => attr.kind(),
99 }
100 }
101
102 fn emit_value(&self, buffer: &mut [u8]) {
103 use self::Nla::*;
104 match self {
105 Unspec(ref bytes)
106 | Destination(ref bytes)
107 | Source(ref bytes)
108 | Pad(ref bytes)
109 | UidRange(ref bytes)
110 | SourcePortRange(ref bytes)
111 | DestinationPortRange(ref bytes) => {
112 buffer.copy_from_slice(bytes.as_slice())
113 }
114 Iifname(ref s) | OifName(ref s) => {
115 buffer[..s.len()].copy_from_slice(s.as_bytes())
116 }
117
118 Priority(value)
119 | FwMark(value)
120 | FwMask(value)
121 | Flow(value)
122 | TunId(value)
123 | Goto(value)
124 | SuppressIfGroup(value)
125 | SuppressPrefixLen(value)
126 | Table(value) => NativeEndian::write_u32(buffer, *value),
127 L3MDev(value) | Protocol(value) | IpProto(value) => {
128 buffer[0] = *value
129 }
130 Other(attr) => attr.emit_value(buffer),
131 }
132 }
133}
134
135impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Nla {
136 fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
137 use Nla::*;
138
139 let payload = buf.value();
140
141 Ok(match buf.kind() {
142 FRA_UNSPEC => Unspec(payload.to_vec()),
143 FRA_DST => Destination(payload.to_vec()),
144 FRA_SRC => Source(payload.to_vec()),
145 FRA_IIFNAME => Iifname(
146 parse_string(payload).context("invalid FRA_IIFNAME value")?,
147 ),
148 FRA_GOTO => {
149 Goto(parse_u32(payload).context("invalid FRA_GOTO value")?)
150 }
151 FRA_PRIORITY => Priority(
152 parse_u32(payload).context("invalid FRA_PRIORITY value")?,
153 ),
154 FRA_FWMARK => {
155 FwMark(parse_u32(payload).context("invalid FRA_FWMARK value")?)
156 }
157 FRA_FLOW => {
158 Flow(parse_u32(payload).context("invalid FRA_FLOW value")?)
159 }
160 FRA_TUN_ID => {
161 TunId(parse_u32(payload).context("invalid FRA_TUN_ID value")?)
162 }
163 FRA_SUPPRESS_IFGROUP => SuppressIfGroup(
164 parse_u32(payload)
165 .context("invalid FRA_SUPPRESS_IFGROUP value")?,
166 ),
167 FRA_SUPPRESS_PREFIXLEN => SuppressPrefixLen(
168 parse_u32(payload)
169 .context("invalid FRA_SUPPRESS_PREFIXLEN value")?,
170 ),
171 FRA_TABLE => {
172 Table(parse_u32(payload).context("invalid FRA_TABLE value")?)
173 }
174 FRA_FWMASK => {
175 FwMask(parse_u32(payload).context("invalid FRA_FWMASK value")?)
176 }
177 FRA_OIFNAME => OifName(
178 parse_string(payload).context("invalid FRA_OIFNAME value")?,
179 ),
180 FRA_PAD => Pad(payload.to_vec()),
181 FRA_L3MDEV => {
182 L3MDev(parse_u8(payload).context("invalid FRA_L3MDEV value")?)
183 }
184 FRA_UID_RANGE => UidRange(payload.to_vec()),
185 FRA_PROTOCOL => Protocol(
186 parse_u8(payload).context("invalid FRA_PROTOCOL value")?,
187 ),
188 FRA_IP_PROTO => IpProto(
189 parse_u8(payload).context("invalid FRA_IP_PROTO value")?,
190 ),
191 FRA_SPORT_RANGE => SourcePortRange(payload.to_vec()),
192 FRA_DPORT_RANGE => DestinationPortRange(payload.to_vec()),
193 _ => Other(
194 DefaultNla::parse(buf).context("invalid NLA (unknown kind)")?,
195 ),
196 })
197 }
198}