1use crate::errors::{Result, SandboxError};
8use serde::{Deserialize, Serialize};
9use std::net::{IpAddr, Ipv4Addr, SocketAddr};
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct NetworkInterface {
14 pub name: String,
16 pub ipv4: Ipv4Addr,
18 pub netmask: Ipv4Addr,
20 pub gateway: Option<Ipv4Addr>,
22 pub enabled: bool,
24}
25
26impl Default for NetworkInterface {
27 fn default() -> Self {
28 Self {
29 name: "eth0".to_string(),
30 ipv4: Ipv4Addr::new(172, 17, 0, 2),
31 netmask: Ipv4Addr::new(255, 255, 255, 0),
32 gateway: Some(Ipv4Addr::new(172, 17, 0, 1)),
33 enabled: true,
34 }
35 }
36}
37
38impl NetworkInterface {
39 pub fn new(name: &str, ipv4: Ipv4Addr) -> Self {
41 Self {
42 name: name.to_string(),
43 ipv4,
44 netmask: Ipv4Addr::new(255, 255, 255, 0),
45 gateway: Some(Ipv4Addr::new(172, 17, 0, 1)),
46 enabled: true,
47 }
48 }
49
50 pub fn validate(&self) -> Result<()> {
52 if self.name.is_empty() {
53 return Err(SandboxError::InvalidConfig(
54 "Interface name cannot be empty".to_string(),
55 ));
56 }
57
58 if self.ipv4.is_unspecified() || self.ipv4.is_broadcast() {
60 return Err(SandboxError::InvalidConfig(
61 "Invalid IP address for interface".to_string(),
62 ));
63 }
64
65 Ok(())
66 }
67
68 pub fn get_cidr(&self) -> String {
70 format!("{}/{}", self.ipv4, self.netmask_bits())
71 }
72
73 pub fn netmask_bits(&self) -> u8 {
75 let octets = self.netmask.octets();
76 let mut bits = 0u8;
77
78 for octet in octets {
79 bits += octet.count_ones() as u8;
80 }
81
82 bits
83 }
84}
85
86#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
88pub enum NetworkMode {
89 #[default]
91 Isolated,
92 Bridge,
94 Host,
96 Custom,
98}
99
100impl std::fmt::Display for NetworkMode {
101 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102 match self {
103 NetworkMode::Isolated => write!(f, "isolated"),
104 NetworkMode::Bridge => write!(f, "bridge"),
105 NetworkMode::Host => write!(f, "host"),
106 NetworkMode::Custom => write!(f, "custom"),
107 }
108 }
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize)]
113pub struct NetworkConfig {
114 pub mode: NetworkMode,
116 pub interfaces: Vec<NetworkInterface>,
118 pub dns_servers: Vec<IpAddr>,
120 pub port_mappings: Vec<PortMapping>,
122 pub ip_forward: bool,
124 pub bandwidth_limit: u64,
126}
127
128impl Default for NetworkConfig {
129 fn default() -> Self {
130 Self {
131 mode: NetworkMode::Isolated,
132 interfaces: vec![NetworkInterface::default()],
133 dns_servers: vec![
134 IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8)),
135 IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1)),
136 ],
137 port_mappings: Vec::new(),
138 ip_forward: false,
139 bandwidth_limit: 0,
140 }
141 }
142}
143
144impl NetworkConfig {
145 pub fn isolated() -> Self {
147 Self {
148 mode: NetworkMode::Isolated,
149 interfaces: vec![],
150 dns_servers: vec![],
151 port_mappings: Vec::new(),
152 ip_forward: false,
153 bandwidth_limit: 0,
154 }
155 }
156
157 pub fn host() -> Self {
159 Self {
160 mode: NetworkMode::Host,
161 interfaces: Vec::new(),
162 dns_servers: Vec::new(),
163 port_mappings: Vec::new(),
164 ip_forward: true,
165 bandwidth_limit: 0,
166 }
167 }
168
169 pub fn add_interface(&mut self, iface: NetworkInterface) -> Result<()> {
171 iface.validate()?;
172 self.interfaces.push(iface);
173 Ok(())
174 }
175
176 pub fn add_port_mapping(&mut self, mapping: PortMapping) -> Result<()> {
178 mapping.validate()?;
179 self.port_mappings.push(mapping);
180 Ok(())
181 }
182
183 pub fn validate(&self) -> Result<()> {
185 for iface in &self.interfaces {
186 iface.validate()?;
187 }
188
189 for mapping in &self.port_mappings {
190 mapping.validate()?;
191 }
192
193 Ok(())
194 }
195}
196
197#[derive(Debug, Clone, Serialize, Deserialize)]
199pub struct PortMapping {
200 pub container_port: u16,
202 pub host_port: u16,
204 pub protocol: String,
206}
207
208impl PortMapping {
209 pub fn new(container_port: u16, host_port: u16) -> Self {
211 Self {
212 container_port,
213 host_port,
214 protocol: "tcp".to_string(),
215 }
216 }
217
218 pub fn validate(&self) -> Result<()> {
220 if self.container_port == 0 || self.host_port == 0 {
221 return Err(SandboxError::InvalidConfig(
222 "Port numbers must be > 0".to_string(),
223 ));
224 }
225
226 if !["tcp", "udp"].contains(&self.protocol.as_str()) {
227 return Err(SandboxError::InvalidConfig(
228 "Protocol must be tcp or udp".to_string(),
229 ));
230 }
231
232 Ok(())
233 }
234
235 pub fn get_host_addr(&self) -> SocketAddr {
237 SocketAddr::from((Ipv4Addr::LOCALHOST, self.host_port))
238 }
239
240 pub fn get_container_addr(&self, ip: Ipv4Addr) -> SocketAddr {
242 SocketAddr::from((ip, self.container_port))
243 }
244}
245
246#[derive(Debug, Clone, Default, Serialize, Deserialize)]
248pub struct NetworkStats {
249 pub bytes_recv: u64,
251 pub bytes_sent: u64,
253 pub packets_recv: u64,
255 pub packets_sent: u64,
257 pub errors: u64,
259 pub dropped: u64,
261}
262
263#[cfg(test)]
264mod tests {
265 use super::*;
266
267 #[test]
268 fn test_network_interface_creation() {
269 let iface = NetworkInterface::new("eth0", Ipv4Addr::new(192, 168, 1, 10));
270 assert_eq!(iface.name, "eth0");
271 assert_eq!(iface.ipv4, Ipv4Addr::new(192, 168, 1, 10));
272 }
273
274 #[test]
275 fn test_network_interface_validation() {
276 let mut iface = NetworkInterface::default();
277 assert!(iface.validate().is_ok());
278
279 iface.ipv4 = Ipv4Addr::UNSPECIFIED;
280 assert!(iface.validate().is_err());
281 }
282
283 #[test]
284 fn test_network_interface_cidr() {
285 let iface = NetworkInterface::default();
286 let cidr = iface.get_cidr();
287 assert!(cidr.contains("/"));
288 }
289
290 #[test]
291 fn test_netmask_bits() {
292 let iface = NetworkInterface {
293 netmask: Ipv4Addr::new(255, 255, 255, 0),
294 ..Default::default()
295 };
296 assert_eq!(iface.netmask_bits(), 24);
297 }
298
299 #[test]
300 fn test_network_mode_display() {
301 assert_eq!(NetworkMode::Isolated.to_string(), "isolated");
302 assert_eq!(NetworkMode::Bridge.to_string(), "bridge");
303 assert_eq!(NetworkMode::Host.to_string(), "host");
304 }
305
306 #[test]
307 fn test_network_config_default() {
308 let config = NetworkConfig::default();
309 assert_eq!(config.mode, NetworkMode::Isolated);
310 assert!(!config.interfaces.is_empty());
311 }
312
313 #[test]
314 fn test_network_config_isolated() {
315 let config = NetworkConfig::isolated();
316 assert_eq!(config.mode, NetworkMode::Isolated);
317 }
318
319 #[test]
320 fn test_network_config_host() {
321 let config = NetworkConfig::host();
322 assert_eq!(config.mode, NetworkMode::Host);
323 assert!(config.ip_forward);
324 }
325
326 #[test]
327 fn test_port_mapping_creation() {
328 let mapping = PortMapping::new(8080, 8080);
329 assert_eq!(mapping.container_port, 8080);
330 assert_eq!(mapping.host_port, 8080);
331 }
332
333 #[test]
334 fn test_port_mapping_validation() {
335 let mapping = PortMapping::new(8080, 8080);
336 assert!(mapping.validate().is_ok());
337
338 let bad_mapping = PortMapping {
339 container_port: 0,
340 host_port: 8080,
341 protocol: "tcp".to_string(),
342 };
343 assert!(bad_mapping.validate().is_err());
344 }
345
346 #[test]
347 fn test_port_mapping_addresses() {
348 let mapping = PortMapping::new(8080, 8080);
349 let host_addr = mapping.get_host_addr();
350 assert_eq!(host_addr.port(), 8080);
351 }
352
353 #[test]
354 fn test_network_stats_default() {
355 let stats = NetworkStats::default();
356 assert_eq!(stats.bytes_recv, 0);
357 assert_eq!(stats.bytes_sent, 0);
358 }
359}