netlink_packet_route/rtnl/rule/nlas/
mod.rs

1// SPDX-License-Identifier: MIT
2
3use 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 address
23    Destination(Vec<u8>),
24    /// source address
25    Source(Vec<u8>),
26    /// input interface name
27    Iifname(String),
28    /// target to jump to when used with rule action `FR_ACT_GOTO`
29    Goto(u32),
30    Priority(u32),
31    FwMark(u32),
32    FwMask(u32),
33    /// flow class id,
34    Flow(u32),
35    TunId(u32),
36    SuppressIfGroup(u32),
37    SuppressPrefixLen(u32),
38    Table(u32),
39    /// output interface name
40    OifName(String),
41    Pad(Vec<u8>),
42    /// iif or oif is l3mdev goto its table
43    L3MDev(u8),
44    UidRange(Vec<u8>),
45    /// RTPROT_*
46    Protocol(u8),
47    /// AF_*
48    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}