1use std::{
4 marker::PhantomData,
5 net::{Ipv4Addr, Ipv6Addr},
6};
7
8use futures_util::stream::StreamExt;
9use netlink_packet_core::{
10 NetlinkMessage, NLM_F_ACK, NLM_F_CREATE, NLM_F_EXCL, NLM_F_REPLACE,
11 NLM_F_REQUEST,
12};
13use netlink_packet_route::{
14 route::RouteHeader,
15 rule::{RuleAction, RuleAttribute, RuleMessage},
16 AddressFamily, RouteNetlinkMessage,
17};
18
19use crate::{try_nl, Error, Handle};
20
21#[derive(Debug, Clone)]
24pub struct RuleAddRequest<T = ()> {
25 handle: Handle,
26 message: RuleMessage,
27 replace: bool,
28 _phantom: PhantomData<T>,
29}
30
31impl<T> RuleAddRequest<T> {
32 pub(crate) fn new(handle: Handle) -> Self {
33 let mut message = RuleMessage::default();
34
35 message.header.table = RouteHeader::RT_TABLE_MAIN;
36 message.header.action = RuleAction::Unspec;
37
38 RuleAddRequest {
39 handle,
40 message,
41 replace: false,
42 _phantom: Default::default(),
43 }
44 }
45
46 pub fn input_interface(mut self, ifname: String) -> Self {
48 self.message.attributes.push(RuleAttribute::Iifname(ifname));
49 self
50 }
51
52 pub fn output_interface(mut self, ifname: String) -> Self {
54 self.message.attributes.push(RuleAttribute::Oifname(ifname));
55 self
56 }
57
58 #[deprecated(note = "Please use `table_id` instead")]
62 pub fn table(mut self, table: u8) -> Self {
63 self.message.header.table = table;
64 self
65 }
66
67 pub fn table_id(mut self, table: u32) -> Self {
71 if table > 255 {
72 self.message.attributes.push(RuleAttribute::Table(table));
73 } else {
74 self.message.header.table = table as u8;
75 }
76 self
77 }
78
79 pub fn tos(mut self, tos: u8) -> Self {
81 self.message.header.tos = tos;
82 self
83 }
84
85 pub fn action(mut self, action: RuleAction) -> Self {
87 self.message.header.action = action;
88 self
89 }
90
91 pub fn priority(mut self, priority: u32) -> Self {
93 self.message
94 .attributes
95 .push(RuleAttribute::Priority(priority));
96 self
97 }
98
99 pub fn fw_mark(mut self, fw_mark: u32) -> Self {
101 self.message.attributes.push(RuleAttribute::FwMark(fw_mark));
102 self
103 }
104
105 pub fn v4(mut self) -> RuleAddRequest<Ipv4Addr> {
107 self.message.header.family = AddressFamily::Inet;
108 RuleAddRequest {
109 handle: self.handle,
110 message: self.message,
111 replace: false,
112 _phantom: Default::default(),
113 }
114 }
115
116 pub fn v6(mut self) -> RuleAddRequest<Ipv6Addr> {
118 self.message.header.family = AddressFamily::Inet6;
119 RuleAddRequest {
120 handle: self.handle,
121 message: self.message,
122 replace: false,
123 _phantom: Default::default(),
124 }
125 }
126
127 pub fn replace(self) -> Self {
129 Self {
130 replace: true,
131 ..self
132 }
133 }
134
135 pub async fn execute(self) -> Result<(), Error> {
137 let RuleAddRequest {
138 mut handle,
139 message,
140 replace,
141 ..
142 } = self;
143 let mut req =
144 NetlinkMessage::from(RouteNetlinkMessage::NewRule(message));
145 let replace = if replace { NLM_F_REPLACE } else { NLM_F_EXCL };
146 req.header.flags = NLM_F_REQUEST | NLM_F_ACK | replace | NLM_F_CREATE;
147
148 let mut response = handle.request(req)?;
149 while let Some(message) = response.next().await {
150 try_nl!(message);
151 }
152
153 Ok(())
154 }
155
156 pub fn message_mut(&mut self) -> &mut RuleMessage {
157 &mut self.message
158 }
159}
160
161impl RuleAddRequest<Ipv4Addr> {
162 pub fn source_prefix(mut self, addr: Ipv4Addr, prefix_length: u8) -> Self {
164 self.message.header.src_len = prefix_length;
165 self.message
166 .attributes
167 .push(RuleAttribute::Source(addr.into()));
168 self
169 }
170
171 pub fn destination_prefix(
173 mut self,
174 addr: Ipv4Addr,
175 prefix_length: u8,
176 ) -> Self {
177 self.message.header.dst_len = prefix_length;
178 self.message
179 .attributes
180 .push(RuleAttribute::Destination(addr.into()));
181 self
182 }
183}
184
185impl RuleAddRequest<Ipv6Addr> {
186 pub fn source_prefix(mut self, addr: Ipv6Addr, prefix_length: u8) -> Self {
188 self.message.header.src_len = prefix_length;
189 self.message
190 .attributes
191 .push(RuleAttribute::Source(addr.into()));
192 self
193 }
194
195 pub fn destination_prefix(
197 mut self,
198 addr: Ipv6Addr,
199 prefix_length: u8,
200 ) -> Self {
201 self.message.header.dst_len = prefix_length;
202 self.message
203 .attributes
204 .push(RuleAttribute::Destination(addr.into()));
205 self
206 }
207}