1use 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
19pub 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 pub fn input_interface(mut self, ifname: String) -> Self {
44 self.message.nlas.push(Nla::Iifname(ifname));
45 self
46 }
47
48 pub fn output_interface(mut self, ifname: String) -> Self {
50 self.message.nlas.push(Nla::OifName(ifname));
51 self
52 }
53
54 pub fn table(mut self, table: u8) -> Self {
58 self.message.header.table = table;
59 self
60 }
61
62 pub fn tos(mut self, tos: u8) -> Self {
64 self.message.header.tos = tos;
65 self
66 }
67
68 pub fn action(mut self, action: u8) -> Self {
70 self.message.header.action = action;
71 self
72 }
73
74 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 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 pub fn replace(self) -> Self {
98 Self {
99 replace: true,
100 ..self
101 }
102 }
103
104 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 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 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 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 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}