1use futures::stream::StreamExt;
4use std::{
5 marker::PhantomData,
6 net::{Ipv4Addr, Ipv6Addr},
7};
8
9use netlink_packet_core::{
10 NetlinkMessage, NLM_F_ACK, NLM_F_CREATE, NLM_F_EXCL, NLM_F_REPLACE,
11 NLM_F_REQUEST,
12};
13
14use netlink_packet_route::{
15 nlas::rule::Nla, RtnlMessage, RuleMessage, AF_INET, AF_INET6,
16 FR_ACT_UNSPEC, RT_TABLE_MAIN,
17};
18
19use crate::{try_nl, Error, Handle};
20
21pub struct RuleAddRequest<T = ()> {
24 handle: Handle,
25 message: RuleMessage,
26 replace: bool,
27 _phantom: PhantomData<T>,
28}
29
30impl<T> RuleAddRequest<T> {
31 pub(crate) fn new(handle: Handle) -> Self {
32 let mut message = RuleMessage::default();
33
34 message.header.table = RT_TABLE_MAIN;
35 message.header.action = FR_ACT_UNSPEC;
36
37 RuleAddRequest {
38 handle,
39 message,
40 replace: false,
41 _phantom: Default::default(),
42 }
43 }
44
45 pub fn input_interface(mut self, ifname: String) -> Self {
47 self.message.nlas.push(Nla::Iifname(ifname));
48 self
49 }
50
51 pub fn output_interface(mut self, ifname: String) -> Self {
53 self.message.nlas.push(Nla::OifName(ifname));
54 self
55 }
56
57 #[deprecated(note = "Please use `table_id` instead")]
61 pub fn table(mut self, table: u8) -> Self {
62 self.message.header.table = table;
63 self
64 }
65
66 pub fn table_id(mut self, table: u32) -> Self {
70 if table > 255 {
71 self.message.nlas.push(Nla::Table(table));
72 } else {
73 self.message.header.table = table as u8;
74 }
75 self
76 }
77
78 pub fn tos(mut self, tos: u8) -> Self {
80 self.message.header.tos = tos;
81 self
82 }
83
84 pub fn action(mut self, action: u8) -> Self {
86 self.message.header.action = action;
87 self
88 }
89
90 pub fn priority(mut self, priority: u32) -> Self {
92 self.message.nlas.push(Nla::Priority(priority));
93 self
94 }
95
96 pub fn v4(mut self) -> RuleAddRequest<Ipv4Addr> {
98 self.message.header.family = AF_INET as u8;
99 RuleAddRequest {
100 handle: self.handle,
101 message: self.message,
102 replace: false,
103 _phantom: Default::default(),
104 }
105 }
106
107 pub fn v6(mut self) -> RuleAddRequest<Ipv6Addr> {
109 self.message.header.family = AF_INET6 as u8;
110 RuleAddRequest {
111 handle: self.handle,
112 message: self.message,
113 replace: false,
114 _phantom: Default::default(),
115 }
116 }
117
118 pub fn replace(self) -> Self {
120 Self {
121 replace: true,
122 ..self
123 }
124 }
125
126 pub async fn execute(self) -> Result<(), Error> {
128 let RuleAddRequest {
129 mut handle,
130 message,
131 replace,
132 ..
133 } = self;
134 let mut req = NetlinkMessage::from(RtnlMessage::NewRule(message));
135 let replace = if replace { NLM_F_REPLACE } else { NLM_F_EXCL };
136 req.header.flags = NLM_F_REQUEST | NLM_F_ACK | replace | NLM_F_CREATE;
137
138 let mut response = handle.request(req)?;
139 while let Some(message) = response.next().await {
140 try_nl!(message);
141 }
142
143 Ok(())
144 }
145
146 pub fn message_mut(&mut self) -> &mut RuleMessage {
147 &mut self.message
148 }
149}
150
151impl RuleAddRequest<Ipv4Addr> {
152 pub fn source_prefix(mut self, addr: Ipv4Addr, prefix_length: u8) -> Self {
154 self.message.header.src_len = prefix_length;
155 let src = addr.octets().to_vec();
156 self.message.nlas.push(Nla::Source(src));
157 self
158 }
159
160 pub fn destination_prefix(
162 mut self,
163 addr: Ipv4Addr,
164 prefix_length: u8,
165 ) -> Self {
166 self.message.header.dst_len = prefix_length;
167 let dst = addr.octets().to_vec();
168 self.message.nlas.push(Nla::Destination(dst));
169 self
170 }
171}
172
173impl RuleAddRequest<Ipv6Addr> {
174 pub fn source_prefix(mut self, addr: Ipv6Addr, prefix_length: u8) -> Self {
176 self.message.header.src_len = prefix_length;
177 let src = addr.octets().to_vec();
178 self.message.nlas.push(Nla::Source(src));
179 self
180 }
181
182 pub fn destination_prefix(
184 mut self,
185 addr: Ipv6Addr,
186 prefix_length: u8,
187 ) -> Self {
188 self.message.header.dst_len = prefix_length;
189 let dst = addr.octets().to_vec();
190 self.message.nlas.push(Nla::Destination(dst));
191 self
192 }
193}