netlink_packet_route/rule/
attribute.rs

1// SPDX-License-Identifier: MIT
2
3use 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;
16// const FRA_UNUSED2: u16 = 5;
17const FRA_PRIORITY: u16 = 6;
18// const FRA_UNUSED3: u16 = 7;
19// const FRA_UNUSED4: u16 = 8;
20// const FRA_UNUSED5: u16 = 9;
21const 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;
29// const FRA_PAD: u16 = 18;
30const 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 address
41    Destination(IpAddr),
42    /// source address
43    Source(IpAddr),
44    /// input interface name
45    Iifname(String),
46    /// The priority number of another rule for [super::RuleAction::Goto]
47    Goto(u32),
48    Priority(u32),
49    FwMark(u32),
50    FwMask(u32),
51    /// IPv4 route realm
52    Realm(RouteRealm),
53    TunId(u32),
54    SuppressIfGroup(u32),
55    SuppressPrefixLen(u32),
56    Table(u32),
57    /// output interface name
58    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}