pub mod datapath_loop;
pub mod nat;
pub mod tun;
pub use arcbox_fakeip::{dns_log, proxy_detect};
pub use arcbox_proxy::{egress, http_connect, inbound_relay, socks5};
pub use splicetcp::{classifier, tcp_bridge};
#[cfg(feature = "vmnet")]
pub use arcbox_vmnet::VmnetRelay;
pub use arcbox_vmnet::{Vmnet, VmnetConfig, VmnetInterfaceInfo, VmnetMode};
pub use nat::DarwinNatNetwork;
pub use tun::DarwinTun;
use std::net::Ipv4Addr;
use crate::error::Result;
use crate::nat::NatConfig;
#[derive(Debug, Clone)]
pub struct DarwinNetConfig {
pub mode: DarwinNetMode,
pub nat_config: Option<NatConfig>,
pub bridge_interface: Option<String>,
pub high_performance: bool,
}
impl Default for DarwinNetConfig {
fn default() -> Self {
Self {
mode: DarwinNetMode::Nat,
nat_config: Some(NatConfig::default()),
bridge_interface: None,
high_performance: true,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum DarwinNetMode {
#[default]
Nat,
HostOnly,
Bridged,
}
#[derive(Debug)]
pub struct DarwinNetEndpoint {
pub id: String,
pub mac: [u8; 6],
pub ip: Option<Ipv4Addr>,
pub mode: DarwinNetMode,
}
impl DarwinNetEndpoint {
#[must_use]
pub fn new(id: String, mac: [u8; 6], mode: DarwinNetMode) -> Self {
Self {
id,
mac,
ip: None,
mode,
}
}
pub fn set_ip(&mut self, ip: Ipv4Addr) {
self.ip = Some(ip);
}
}
#[must_use]
pub fn generate_mac() -> [u8; 6] {
use std::time::{SystemTime, UNIX_EPOCH};
let seed = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_nanos() as u64;
let mut state = seed;
let mut mac = [0u8; 6];
for byte in &mut mac {
state = state.wrapping_mul(6364136223846793005).wrapping_add(1);
*byte = (state >> 32) as u8;
}
mac[0] = (mac[0] & 0xFC) | 0x02;
mac
}
#[must_use]
pub fn format_mac(mac: &[u8; 6]) -> String {
format!(
"{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
)
}
pub fn parse_mac(s: &str) -> Result<[u8; 6]> {
let parts: Vec<&str> = s.split(':').collect();
if parts.len() != 6 {
return Err(crate::error::NetError::config(
"invalid MAC address format".to_string(),
));
}
let mut mac = [0u8; 6];
for (i, part) in parts.iter().enumerate() {
mac[i] = u8::from_str_radix(part, 16)
.map_err(|_| crate::error::NetError::config("invalid MAC address byte".to_string()))?;
}
Ok(mac)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_generate_mac() {
let mac1 = generate_mac();
std::thread::sleep(std::time::Duration::from_micros(1));
let mac2 = generate_mac();
assert_eq!(mac1[0] & 0x02, 0x02);
assert_eq!(mac1[0] & 0x01, 0x00);
assert_ne!(mac1, mac2);
}
#[test]
fn test_format_mac() {
let mac = [0x02, 0xAB, 0xCD, 0xEF, 0x12, 0x34];
assert_eq!(format_mac(&mac), "02:ab:cd:ef:12:34");
}
#[test]
fn test_parse_mac() {
let mac = parse_mac("02:ab:cd:ef:12:34").unwrap();
assert_eq!(mac, [0x02, 0xAB, 0xCD, 0xEF, 0x12, 0x34]);
}
#[test]
fn test_parse_mac_invalid() {
assert!(parse_mac("invalid").is_err());
assert!(parse_mac("02:ab:cd:ef:12").is_err()); assert!(parse_mac("02:ab:cd:ef:12:34:56").is_err()); assert!(parse_mac("02:ab:cd:ef:12:gg").is_err()); }
#[test]
fn test_roundtrip_mac() {
let original = [0x02, 0xAB, 0xCD, 0xEF, 0x12, 0x34];
let formatted = format_mac(&original);
let parsed = parse_mac(&formatted).unwrap();
assert_eq!(original, parsed);
}
}