rtnetlink/rule/
add.rs

1// SPDX-License-Identifier: MIT
2
3use futures::stream::StreamExt;
4use std::{
5    marker::PhantomData,
6    net::{Ipv4Addr, Ipv6Addr},
7};
8
9use netlink_packet_route::{
10    constants::*,
11    nlas::rule::Nla,
12    NetlinkMessage,
13    RtnlMessage,
14    RuleMessage,
15};
16
17use crate::{try_nl, Error, Handle};
18
19/// A request to create a new rule. This is equivalent to the `ip rule add` command.
20pub struct RuleAddRequest<T = ()> {
21    handle: Handle,
22    message: RuleMessage,
23    replace: bool,
24    _phantom: PhantomData<T>,
25}
26
27impl<T> RuleAddRequest<T> {
28    pub(crate) fn new(handle: Handle) -> Self {
29        let mut message = RuleMessage::default();
30
31        message.header.table = RT_TABLE_MAIN;
32        message.header.action = FR_ACT_UNSPEC;
33
34        RuleAddRequest {
35            handle,
36            message,
37            replace: false,
38            _phantom: Default::default(),
39        }
40    }
41
42    /// Sets the input interface name.
43    pub fn input_interface(mut self, ifname: String) -> Self {
44        self.message.nlas.push(Nla::Iifname(ifname));
45        self
46    }
47
48    /// Sets the output interface name.
49    pub fn output_interface(mut self, ifname: String) -> Self {
50        self.message.nlas.push(Nla::OifName(ifname));
51        self
52    }
53
54    /// Sets the rule table.
55    ///
56    /// Default is main rule table.
57    pub fn table(mut self, table: u8) -> Self {
58        self.message.header.table = table;
59        self
60    }
61
62    /// Set the tos.
63    pub fn tos(mut self, tos: u8) -> Self {
64        self.message.header.tos = tos;
65        self
66    }
67
68    /// Set action.
69    pub fn action(mut self, action: u8) -> Self {
70        self.message.header.action = action;
71        self
72    }
73
74    /// Build an IP v4 rule
75    pub fn v4(mut self) -> RuleAddRequest<Ipv4Addr> {
76        self.message.header.family = AF_INET as u8;
77        RuleAddRequest {
78            handle: self.handle,
79            message: self.message,
80            replace: false,
81            _phantom: Default::default(),
82        }
83    }
84
85    /// Build an IP v6 rule
86    pub fn v6(mut self) -> RuleAddRequest<Ipv6Addr> {
87        self.message.header.family = AF_INET6 as u8;
88        RuleAddRequest {
89            handle: self.handle,
90            message: self.message,
91            replace: false,
92            _phantom: Default::default(),
93        }
94    }
95
96    /// Replace existing matching rule.
97    pub fn replace(self) -> Self {
98        Self {
99            replace: true,
100            ..self
101        }
102    }
103
104    /// Execute the request.
105    pub async fn execute(self) -> Result<(), Error> {
106        let RuleAddRequest {
107            mut handle,
108            message,
109            replace,
110            ..
111        } = self;
112        let mut req = NetlinkMessage::from(RtnlMessage::NewRule(message));
113        let replace = if replace { NLM_F_REPLACE } else { NLM_F_EXCL };
114        req.header.flags = NLM_F_REQUEST | NLM_F_ACK | replace | NLM_F_CREATE;
115
116        let mut response = handle.request(req)?;
117        while let Some(message) = response.next().await {
118            try_nl!(message);
119        }
120
121        Ok(())
122    }
123
124    pub fn message_mut(&mut self) -> &mut RuleMessage {
125        &mut self.message
126    }
127}
128
129impl RuleAddRequest<Ipv4Addr> {
130    /// Sets the source address prefix.
131    pub fn source_prefix(mut self, addr: Ipv4Addr, prefix_length: u8) -> Self {
132        self.message.header.src_len = prefix_length;
133        let src = addr.octets().to_vec();
134        self.message.nlas.push(Nla::Source(src));
135        self
136    }
137
138    /// Sets the destination address prefix.
139    pub fn destination_prefix(mut self, addr: Ipv4Addr, prefix_length: u8) -> Self {
140        self.message.header.dst_len = prefix_length;
141        let dst = addr.octets().to_vec();
142        self.message.nlas.push(Nla::Destination(dst));
143        self
144    }
145}
146
147impl RuleAddRequest<Ipv6Addr> {
148    /// Sets the source address prefix.
149    pub fn source_prefix(mut self, addr: Ipv6Addr, prefix_length: u8) -> Self {
150        self.message.header.src_len = prefix_length;
151        let src = addr.octets().to_vec();
152        self.message.nlas.push(Nla::Source(src));
153        self
154    }
155
156    /// Sets the destination address prefix.
157    pub fn destination_prefix(mut self, addr: Ipv6Addr, prefix_length: u8) -> Self {
158        self.message.header.dst_len = prefix_length;
159        let dst = addr.octets().to_vec();
160        self.message.nlas.push(Nla::Destination(dst));
161        self
162    }
163}