3
3
use std:: {
4
4
io,
5
5
net:: {
6
+ IpAddr ,
6
7
Ipv4Addr ,
7
8
SocketAddrV4 ,
8
9
} ,
@@ -32,8 +33,20 @@ use pnet::{
32
33
} ,
33
34
} ;
34
35
36
+ use tokio:: task;
37
+
38
+ use proton_mac:: MacAddrPolicy ;
39
+
35
40
use proton_nat:: NatTable ;
36
41
42
+ use proton_nif:: {
43
+ ifnames:: {
44
+ DEFAULT_WIRED_INTERFACE ,
45
+ DEFAULT_WIRELESS_INTERFACE ,
46
+ } ,
47
+ NetworkInterface ,
48
+ } ;
49
+
37
50
use crate :: AccessPointResult ;
38
51
39
52
/// Transport channel buffer size.
@@ -46,6 +59,9 @@ pub struct AccessPoint {
46
59
47
60
/// CIDR network range.
48
61
range : Ipv4Cidr ,
62
+
63
+ /// MAC address management policy.
64
+ mac_policy : MacAddrPolicy ,
49
65
}
50
66
51
67
impl AccessPoint {
@@ -56,26 +72,67 @@ impl AccessPoint {
56
72
/// to this access point
57
73
/// - `range` (`Ipv4Cidr`): the internal network range associated to
58
74
/// this access point
75
+ /// - `mac_policy` (`MacAddrPolicy`): the MAC address policy of this
76
+ /// access point
59
77
///
60
78
/// # Returns
61
79
/// A new `AccessPoint`.
62
- pub fn new ( external_ipv4 : Ipv4Addr , range : Ipv4Cidr ) -> Self {
80
+ pub fn new (
81
+ external_ipv4 : Ipv4Addr ,
82
+ range : Ipv4Cidr ,
83
+ mac_policy : MacAddrPolicy ,
84
+ ) -> Self {
63
85
Self {
64
86
nat : NatTable :: new ( vec ! [ external_ipv4] ) ,
65
87
range,
88
+ mac_policy,
66
89
}
67
90
}
68
91
69
- /// Continuously route packets on the Transport Layer (OSI Layer 4).
92
+ /// Continuously route packets, monitoring both the Data Link Layer and
93
+ /// the Transport Layer to ensure both proper NAT and MAC policy enforcement.
70
94
///
71
95
/// # Parameters
72
96
/// None.
73
97
///
74
98
/// # Returns
75
- /// An `AccessPointResult` indicating an error, if one occurred.
99
+ /// An `AccessPointResult<()>` indicating an error, if one occurred.
100
+ ///
101
+ /// This function does not return during nominal operation.
102
+ pub async fn run ( & mut self ) -> AccessPointResult < ( ) > {
103
+ // Construct new NAT
104
+ let nat = self . nat . clone ( ) ;
105
+
106
+ // Get network range
107
+ let range = self . range ;
108
+
109
+ // Get MAC policy
110
+ let mac_policy = self . mac_policy . clone ( ) ;
111
+
112
+ let layer_2_task = task:: spawn ( Self :: run_layer_2 ( mac_policy) ) ;
113
+
114
+ let layer_4_task = task:: spawn ( Self :: run_layer_4 ( nat, range) ) ;
115
+
116
+ match tokio:: join!( layer_2_task, layer_4_task) {
117
+ ( Ok ( _) , Ok ( _) ) => Ok ( ( ) ) ,
118
+ _ => todo ! ( ) ,
119
+ }
120
+ }
121
+
122
+ /// Continuously route packets on the Transport Layer (OSI Layer 4).
123
+ ///
124
+ /// # Parameters
125
+ /// - `nat` (`NatTable`): the reference NAT table
126
+ /// - `range` (`Ipv4Cidr`): the network range
127
+ ///
128
+ /// # Returns
129
+ /// An `AccessPointResult<()>` indicating an error, if one occurred.
76
130
///
77
- /// This function does not return if there are no errors.
78
- pub fn run ( & mut self ) -> AccessPointResult {
131
+ /// This function does not return during nominal operation.
132
+ async fn run_layer_4 (
133
+ mut nat : NatTable ,
134
+ range : Ipv4Cidr ,
135
+ ) -> AccessPointResult < ( ) > {
79
136
// Create an IPv4 protocol
80
137
let protocol = Layer4 ( Ipv4 ( IpNextHeaderProtocols :: Ipv4 ) ) ;
81
138
@@ -85,37 +142,22 @@ impl AccessPoint {
85
142
Err ( _) => return Err ( io:: Error :: new ( io:: ErrorKind :: Other , "could not open transport channel" ) ) ,
86
143
} ;
87
144
88
- // We treat received packets as if they were IPv4 packets
145
+ // We treat received packets as if they are IPv4 packets
89
146
let mut iter = ipv4_packet_iter ( & mut rx) ;
90
147
91
148
// Continuously iterate through the packets on the receiving line
92
149
loop {
93
150
match iter. next ( ) {
94
151
Ok ( ( packet, addr) ) => {
95
- // Allocate enough space for a new packet
96
- let mut vec: Vec < u8 > = vec ! [ 0 ; packet. packet( ) . len( ) ] ;
97
- let mut new_packet = MutableIpv4Packet :: new ( & mut vec[ ..] ) . unwrap ( ) ;
98
-
99
- // Create a clone of the original packet
100
- new_packet. clone_from ( & packet) ;
101
-
102
- // Get source IPv4
103
- let source_ipv4: Ipv4Addr = new_packet. get_source ( ) ;
104
-
105
- // Construct immutable packet
106
- let ipv4_packet = new_packet. to_immutable ( ) ;
107
-
108
- // Detect NAT type and translate packet
109
- let translated_packet = if self . range . contains ( & source_ipv4) {
110
- // Source NAT
111
- self . translate_outgoing_ipv4_packet ( ipv4_packet)
112
- } else {
113
- // Destination NAT
114
- self . translate_incoming_ipv4_packet ( ipv4_packet)
115
- } . ok_or ( io:: Error :: new ( io:: ErrorKind :: Other , "could not perform NAT" ) ) ?;
152
+ let ( translated_packet, translated_addr) = Self :: translate_packet (
153
+ & mut nat,
154
+ range,
155
+ packet,
156
+ addr,
157
+ ) ?;
116
158
117
159
// Send the translated packet
118
- if tx. send_to ( translated_packet, addr ) . is_err ( ) {
160
+ if tx. send_to ( translated_packet, translated_addr ) . is_err ( ) {
119
161
println ! ( "Failed to send packet to address {}" , addr) ;
120
162
}
121
163
}
@@ -128,15 +170,135 @@ impl AccessPoint {
128
170
}
129
171
}
130
172
173
+ /// Continuously route frames on the Data Link Layer (OSI Layer 2).
174
+ ///
175
+ /// # Parameters
176
+ /// - `mac_policy` (`MacAddrPolicy`): the MAC address management policy
177
+ ///
178
+ /// # Returns
179
+ /// An `AccessPointResult<()>` indicating an error, if one occurred.
180
+ ///
181
+ /// This function does not return during nominal operation.
182
+ async fn run_layer_2 ( mac_policy : MacAddrPolicy ) -> AccessPointResult < ( ) > {
183
+ // Construct the wired network interface
184
+ let wired_if = NetworkInterface :: new ( DEFAULT_WIRED_INTERFACE )
185
+ . ok_or ( io:: Error :: new ( io:: ErrorKind :: Other , "could not find wired interface" ) ) ?;
186
+
187
+ // Construct the wireless network interface
188
+ let wireless_if = NetworkInterface :: new ( DEFAULT_WIRELESS_INTERFACE )
189
+ . ok_or ( io:: Error :: new ( io:: ErrorKind :: Other , "could not find wireless interface" ) ) ?;
190
+
191
+ // Route outgoing ETH frames
192
+ let outgoing_task = task:: spawn ( Self :: route_outgoing_frames ( wired_if. clone ( ) , wireless_if. clone ( ) , mac_policy) ) ;
193
+
194
+ // Route incoming ETH frames
195
+ let incoming_task = task:: spawn ( Self :: route_incoming_frames ( wired_if, wireless_if) ) ;
196
+
197
+ match tokio:: join!( outgoing_task, incoming_task) {
198
+ ( Ok ( _) , Ok ( _) ) => Ok ( ( ) ) ,
199
+ _ => todo ! ( ) ,
200
+ }
201
+ }
202
+
203
+ /// Route incoming Ethernet frames.
204
+ ///
205
+ /// # Parameters
206
+ /// - `wired_if` (`NetworkInterface`): the wired network interface
207
+ /// - `wireless_if` (`NetworkInterface`): the wireless network interface
208
+ ///
209
+ /// # Returns
210
+ /// TODO
211
+ async fn route_incoming_frames (
212
+ _wired_if : NetworkInterface ,
213
+ _wireless_if : NetworkInterface ,
214
+ ) {
215
+ todo ! ( )
216
+ }
217
+
218
+ /// Route outgoing Ethernet frames.
219
+ ///
220
+ /// # Parameters
221
+ /// - `wired_if` (`NetworkInterface`): the wired network interface
222
+ /// - `wireless_if` (`NetworkInterface`): the wireless network interface
223
+ /// - `mac_policy` (`MacAddrPolicy`): the MAC address management policy
224
+ ///
225
+ /// # Returns
226
+ /// TODO
227
+ async fn route_outgoing_frames (
228
+ _wired_if : NetworkInterface ,
229
+ _wireless_if : NetworkInterface ,
230
+ _mac_policy : MacAddrPolicy ,
231
+ ) {
232
+ todo ! ( )
233
+ }
234
+
235
+ /// Translate an IPv4 packet.
236
+ ///
237
+ /// # Parameters
238
+ /// - `nat` (`&mut NatTable`): the reference NAT table
239
+ /// - `range` (`Ipv4Cidr`): the network range
240
+ /// - `packet` (`Ipv4Packet`): an IPv4 packet to be translated
241
+ /// - `addr` (`IpAddr`): the destination IP address of the packet,
242
+ /// which will change in the case of Destination NAT (DNAT).
243
+ fn translate_packet < ' a > (
244
+ nat : & ' a mut NatTable ,
245
+ range : Ipv4Cidr ,
246
+ packet : Ipv4Packet < ' a > ,
247
+ addr : IpAddr ,
248
+ ) -> AccessPointResult < ( Ipv4Packet < ' a > , IpAddr ) > {
249
+ // Allocate enough space for a new packet
250
+ let mut vec: Vec < u8 > = vec ! [ 0 ; packet. packet( ) . len( ) ] ;
251
+ let mut new_packet = MutableIpv4Packet :: new ( & mut vec[ ..] ) . unwrap ( ) ;
252
+
253
+ // Create a clone of the original packet
254
+ new_packet. clone_from ( & packet) ;
255
+
256
+ // Get source IPv4
257
+ let source_ipv4: Ipv4Addr = new_packet. get_source ( ) ;
258
+
259
+ // Construct immutable packet
260
+ let ipv4_packet = new_packet. to_immutable ( ) ;
261
+
262
+ // Set translated address
263
+ let mut translated_addr = addr;
264
+
265
+ // Detect NAT type and translate packet
266
+ let output_packet = if range. contains ( & source_ipv4) {
267
+ // Source NAT
268
+ Self :: translate_outgoing_ipv4_packet ( nat, ipv4_packet)
269
+ . ok_or ( io:: Error :: new ( io:: ErrorKind :: Other , "could not perform source NAT" ) ) ?
270
+ } else {
271
+ // Destination NAT
272
+ let ( packet, new_addr) = Self :: translate_incoming_ipv4_packet ( nat, ipv4_packet)
273
+ . ok_or ( io:: Error :: new ( io:: ErrorKind :: Other , "could not perform destination NAT" ) ) ?;
274
+
275
+ // Set new destination address
276
+ translated_addr = IpAddr :: V4 ( * new_addr. ip ( ) ) ;
277
+
278
+ packet
279
+ } ;
280
+
281
+ // Clone the translated packet
282
+ let vec: Vec < u8 > = vec ! [ 0 ; packet. packet( ) . len( ) ] ;
283
+ let mut translated_packet = MutableIpv4Packet :: owned ( vec) . unwrap ( ) ;
284
+ translated_packet. clone_from ( & output_packet) ;
285
+
286
+ Ok ( ( translated_packet. consume_to_immutable ( ) , translated_addr) )
287
+ }
288
+
131
289
/// Translate an outgoing IPv4 packet.
132
290
///
133
291
/// # Parameters
292
+ /// - `nat` (`&mut NatTable`): the reference NAT table
134
293
/// - `packet` (`Ipv4Packet`): the IPv4 packet to translate
135
294
///
136
295
/// # Returns
137
296
/// An `Option<IPv4Packet>` with a translated source address and port number, if
138
297
/// translation was successful.
139
- fn translate_outgoing_ipv4_packet ( & mut self , packet : Ipv4Packet ) -> Option < Ipv4Packet > {
298
+ fn translate_outgoing_ipv4_packet < ' a > (
299
+ nat : & ' a mut NatTable ,
300
+ packet : Ipv4Packet < ' a >
301
+ ) -> Option < Ipv4Packet < ' a > > {
140
302
// Construct a mutable IPv4 packet
141
303
let mut ip_packet = MutableIpv4Packet :: owned ( packet. packet ( ) . to_vec ( ) ) ?;
142
304
@@ -153,11 +315,11 @@ impl AccessPoint {
153
315
let source_socket = SocketAddrV4 :: new ( source_ipv4, source_port) ;
154
316
155
317
// Check if the IPv4 address is in the NAT table
156
- let translated_source_socket = if let Some ( i) = self . nat . translate_source ( source_socket) {
318
+ let translated_source_socket = if let Some ( i) = nat. translate_source ( source_socket) {
157
319
i
158
320
} else {
159
321
// Try to add the address to the NAT table
160
- self . nat . add ( source_socket) ?
322
+ nat. add ( source_socket) ?
161
323
} ;
162
324
163
325
// Extract the IPv4 address and port number from the socket
@@ -179,12 +341,16 @@ impl AccessPoint {
179
341
/// Translate an incoming IPv4 packet.
180
342
///
181
343
/// # Parameters
344
+ /// - `nat` (`&mut NatTable`): the reference NAT table
182
345
/// - `packet` (`Ipv4Packet`): the IPv4 packet to translate
183
346
///
184
347
/// # Returns
185
- /// An `Option<IPv4Packet>` with a translated destination address and port number, if
186
- /// translation was successful.
187
- fn translate_incoming_ipv4_packet ( & mut self , packet : Ipv4Packet ) -> Option < Ipv4Packet > {
348
+ /// An `Option<(IPv4Packet, SocketAddrV4)>` with an IPv4 packet with translated destination
349
+ /// address and port number, and the new destination, if translation was successful.
350
+ fn translate_incoming_ipv4_packet < ' a > (
351
+ nat : & ' a mut NatTable ,
352
+ packet : Ipv4Packet < ' a >
353
+ ) -> Option < ( Ipv4Packet < ' a > , SocketAddrV4 ) > {
188
354
// Construct a mutable IPv4 packet
189
355
let mut ip_packet = MutableIpv4Packet :: owned ( packet. packet ( ) . to_vec ( ) ) ?;
190
356
@@ -201,7 +367,7 @@ impl AccessPoint {
201
367
let destination_socket = SocketAddrV4 :: new ( destination_ipv4, destination_port) ;
202
368
203
369
// Check if the IPv4 address is in the NAT table
204
- let translated_destination_socket = self . nat . translate_destination ( destination_socket) ?;
370
+ let translated_destination_socket = nat. translate_destination ( destination_socket) ?;
205
371
206
372
// Extract the IPv4 address and port number from the socket
207
373
let new_ipv4 = translated_destination_socket. ip ( ) ;
@@ -216,6 +382,6 @@ impl AccessPoint {
216
382
// Translate the port number
217
383
tcp_segment. set_destination ( new_port) ;
218
384
219
- Some ( ip_packet. consume_to_immutable ( ) )
385
+ Some ( ( ip_packet. consume_to_immutable ( ) , translated_destination_socket ) )
220
386
}
221
387
}
0 commit comments