1use std::cell::{Cell, RefCell};
2use std::net::{Ipv4Addr, SocketAddrV4};
3use std::ops::{Deref, DerefMut};
4use std::sync::Arc;
5
6use atomic_refcell::AtomicRefCell;
7
8use crate::core::configuration::QDiscMode;
9use crate::core::worker::Worker;
10use crate::host::descriptor::socket::abstract_unix_ns::AbstractUnixNamespace;
11use crate::host::descriptor::socket::inet::InetSocket;
12use crate::host::network::interface::{NetworkInterface, PcapOptions};
13use crate::network::packet::IanaProtocol;
14
15const MIN_RANDOM_PORT: u16 = 10000;
18
19pub struct NetworkNamespace {
26 pub unix: Arc<AtomicRefCell<AbstractUnixNamespace>>,
28
29 pub localhost: RefCell<NetworkInterface>,
30 pub internet: RefCell<NetworkInterface>,
31
32 pub default_ip: Ipv4Addr,
33
34 has_run_cleanup: Cell<bool>,
36}
37
38impl NetworkNamespace {
39 pub fn new(public_ip: Ipv4Addr, pcap: Option<PcapOptions>, qdisc: QDiscMode) -> Self {
40 let localhost = NetworkInterface::new("lo", Ipv4Addr::LOCALHOST, pcap.clone(), qdisc);
41
42 let internet = NetworkInterface::new("eth0", public_ip, pcap, qdisc);
43
44 Self {
45 unix: Arc::new(AtomicRefCell::new(AbstractUnixNamespace::new())),
46 localhost: RefCell::new(localhost),
47 internet: RefCell::new(internet),
48 default_ip: public_ip,
49 has_run_cleanup: Cell::new(false),
50 }
51 }
52
53 pub fn cleanup(&self) {
56 assert!(!self.has_run_cleanup.get());
57
58 self.localhost.borrow().remove_all_sockets();
61 self.internet.borrow().remove_all_sockets();
62
63 self.has_run_cleanup.set(true);
64 }
65
66 #[track_caller]
68 pub fn interface_borrow(
69 &self,
70 addr: Ipv4Addr,
71 ) -> Option<impl Deref<Target = NetworkInterface> + '_> {
72 if addr.is_loopback() {
80 Some(self.localhost.borrow())
81 } else if addr == self.default_ip || addr.is_unspecified() {
82 Some(self.internet.borrow())
83 } else {
84 None
85 }
86 }
87
88 #[track_caller]
90 pub fn interface_borrow_mut(
91 &self,
92 addr: Ipv4Addr,
93 ) -> Option<impl DerefMut<Target = NetworkInterface> + '_> {
94 if addr.is_loopback() {
102 Some(self.localhost.borrow_mut())
103 } else if addr == self.default_ip || addr.is_unspecified() {
104 Some(self.internet.borrow_mut())
105 } else {
106 None
107 }
108 }
109
110 pub fn is_addr_in_use(
111 &self,
112 protocol_type: IanaProtocol,
113 src: SocketAddrV4,
114 dst: SocketAddrV4,
115 ) -> Result<bool, NoInterface> {
116 if src.ip().is_unspecified() {
117 Ok(self
118 .localhost
119 .borrow()
120 .is_addr_in_use(protocol_type, src.port(), dst)
121 || self
122 .internet
123 .borrow()
124 .is_addr_in_use(protocol_type, src.port(), dst))
125 } else {
126 match self.interface_borrow(*src.ip()) {
127 Some(i) => Ok(i.is_addr_in_use(protocol_type, src.port(), dst)),
128 None => Err(NoInterface),
129 }
130 }
131 }
132
133 pub fn get_random_free_port(
135 &self,
136 protocol_type: IanaProtocol,
137 interface_ip: Ipv4Addr,
138 peer: SocketAddrV4,
139 mut rng: impl rand::Rng,
140 ) -> Option<u16> {
141 for _ in 0..10 {
149 let random_port = rng.random_range(MIN_RANDOM_PORT..=u16::MAX);
150
151 let specific_in_use = self
153 .is_addr_in_use(
154 protocol_type,
155 SocketAddrV4::new(interface_ip, random_port),
156 peer,
157 )
158 .unwrap_or(true);
159 let generic_in_use = self
160 .is_addr_in_use(
161 protocol_type,
162 SocketAddrV4::new(interface_ip, random_port),
163 SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0),
164 )
165 .unwrap_or(true);
166 if !specific_in_use && !generic_in_use {
167 return Some(random_port);
168 }
169 }
170
171 let start = rng.random_range(MIN_RANDOM_PORT..=u16::MAX);
175 for port in (start..=u16::MAX).chain(MIN_RANDOM_PORT..start) {
176 let specific_in_use = self
177 .is_addr_in_use(protocol_type, SocketAddrV4::new(interface_ip, port), peer)
178 .unwrap_or(true);
179 let generic_in_use = self
180 .is_addr_in_use(
181 protocol_type,
182 SocketAddrV4::new(interface_ip, port),
183 SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0),
184 )
185 .unwrap_or(true);
186 if !specific_in_use && !generic_in_use {
187 return Some(port);
188 }
189 }
190
191 log::warn!("unable to find free ephemeral port for {protocol_type:?} peer {peer}");
192 None
193 }
194
195 pub unsafe fn associate_interface(
202 &self,
203 socket: &InetSocket,
204 protocol: IanaProtocol,
205 bind_addr: SocketAddrV4,
206 peer_addr: SocketAddrV4,
207 ) -> AssociationHandle {
208 if bind_addr.ip().is_unspecified() {
209 self.localhost
211 .borrow()
212 .associate(socket, protocol, bind_addr.port(), peer_addr);
213 self.internet
214 .borrow()
215 .associate(socket, protocol, bind_addr.port(), peer_addr);
216 } else {
217 if let Some(iface) = self.interface_borrow(*bind_addr.ip()) {
219 iface.associate(socket, protocol, bind_addr.port(), peer_addr);
220 }
221 }
222
223 AssociationHandle {
224 protocol,
225 local_addr: bind_addr,
226 remote_addr: peer_addr,
227 }
228 }
229
230 pub fn disassociate_interface(
236 &self,
237 protocol: IanaProtocol,
238 bind_addr: SocketAddrV4,
239 peer_addr: SocketAddrV4,
240 ) {
241 if bind_addr.ip().is_unspecified() {
242 self.localhost
244 .borrow()
245 .disassociate(protocol, bind_addr.port(), peer_addr);
246
247 self.internet
248 .borrow()
249 .disassociate(protocol, bind_addr.port(), peer_addr);
250 } else {
251 if let Some(iface) = self.interface_borrow(*bind_addr.ip()) {
253 iface.disassociate(protocol, bind_addr.port(), peer_addr);
254 }
255 }
256 }
257}
258
259impl std::ops::Drop for NetworkNamespace {
260 fn drop(&mut self) {
261 if !self.has_run_cleanup.get() && !std::thread::panicking() {
262 debug_panic!("Dropped the network namespace before it has been cleaned up");
263 }
264 }
265}
266
267#[derive(Copy, Clone, Debug, PartialEq, Eq)]
268pub struct NoInterface;
269
270impl std::fmt::Display for NoInterface {
271 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
272 write!(f, "No interface available")
273 }
274}
275
276impl std::error::Error for NoInterface {}
277
278#[derive(Debug)]
283pub struct AssociationHandle {
284 protocol: IanaProtocol,
285 local_addr: SocketAddrV4,
286 remote_addr: SocketAddrV4,
287}
288
289impl AssociationHandle {
290 pub fn local_addr(&self) -> SocketAddrV4 {
291 self.local_addr
292 }
293
294 pub fn remote_addr(&self) -> SocketAddrV4 {
295 self.remote_addr
296 }
297}
298
299impl std::ops::Drop for AssociationHandle {
300 fn drop(&mut self) {
301 Worker::with_active_host(|host| {
302 host.network_namespace_borrow().disassociate_interface(
303 self.protocol,
304 self.local_addr,
305 self.remote_addr,
306 );
307 })
308 .unwrap();
309 }
310}