netlink_packet_route/rtnl/rule/nlas/
mod.rs

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