use etherparse::ether_type::ARP; use etherparse::{Ethernet2Header, IpHeaders}; use sdlan_sn_rs::config::SDLAN_DEFAULT_TTL; use sdlan_sn_rs::utils::{ aes_encrypt, ip_to_string, is_ipv6_multicast, is_multi_broadcast, net_bit_len_to_mask, SDLanError, BROADCAST_MAC, }; use std::error::Error; use std::ffi::CStr; use std::ffi::{c_char, c_int}; use std::fs::OpenOptions; use std::ptr::null_mut; use std::sync::atomic::Ordering; use sdlan_sn_rs::utils::Result; use std::io::{Read, Write}; use std::os::fd::AsRawFd; use std::process::{Command, Output}; use tracing::{debug, error, info}; use crate::get_edge; use crate::network::{ generate_arp_request, send_arp_request, send_packet_to_net, ArpHdr, ArpRequestInfo, ArpResponse, ARP_REPLY, }; use crate::pb::{encode_to_udp_message, SdlData}; use crate::tcp::PacketType; use crate::utils::{caculate_crc, mac_to_string}; use super::device::{DeviceConfig, Mode}; use super::TunTapPacketHandler; #[link(name = "tuntap")] extern "C" { fn tuntap_setup(fd: c_int, name: *mut u8, mode: c_int, packet_info: c_int) -> c_int; } #[allow(unused)] pub struct Iface { fd: std::fs::File, mode: Mode, name: String, } pub fn new_iface(tunname: &str, mode: Mode) -> Iface { match Iface::without_packet_info(tunname, mode) { Err(e) => { panic!("failed to create tun: {}", e.as_str()); } Ok(iface) => iface, } } impl Iface { #[allow(unused)] pub fn with_packet_info(ifname: &str, mode: Mode) -> Result { Iface::open_tun(ifname, mode, true) } pub fn without_packet_info(ifname: &str, mode: Mode) -> Result { Iface::open_tun(ifname, mode, false) } fn open_tun(ifname: &str, mode: Mode, need_packet_info: bool) -> Result { let fs = match OpenOptions::new() .read(true) .write(true) .open("/dev/net/tun") { Ok(fs) => fs, Err(e) => panic!("failed to open tun: {}", e), }; let mut name_ptr: *mut u8 = null_mut(); let mut success = false; let mut _name = Vec::new(); for i in 0..16 { _name = Vec::new(); _name.extend_from_slice(ifname.as_bytes()); _name.extend_from_slice(i.to_string().as_bytes()); _name.extend_from_slice(&[0; 33]); name_ptr = _name.as_mut_ptr(); let result = unsafe { tuntap_setup( fs.as_raw_fd(), name_ptr, mode as c_int, if need_packet_info { 1 } else { 0 }, ) }; if result >= 0 { success = true; break; } } if success { let name = unsafe { CStr::from_ptr(name_ptr as *const c_char) .to_string_lossy() .into_owned() }; Ok(Iface { fd: fs, mode, name }) } else { Err(SDLanError::NormalError("failed to setup tun")) } } pub fn reload_config(&self, device_config: &DeviceConfig) { let netbit = device_config.get_net_bit(); let ip = device_config.get_ip(); if netbit == 0 || ip == 0 { error!("reload config's ip is 0"); return; } let ip = ip_to_string(&ip); let netbit = ip_to_string(&net_bit_len_to_mask(netbit)); if cfg!(feature = "tap") { println!("set tap device"); let mac = device_config.get_mac(); let res = Command::new("ifconfig") .arg(&self.name) .arg(ip) .arg("netmask") .arg(&netbit) .arg("hw") .arg("ether") .arg(format!( "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] )) .arg("up") .output(); match res { Ok(_) => { debug!("ifconfig ok"); } Err(e) => { error!("failed to run ifconfig: {}", e.to_string()); } } } else { println!("set tun device"); let res = Command::new("ifconfig") .arg(&self.name) .arg(ip) .arg("netmask") .arg(&netbit) .arg("up") .output(); match res { Ok(_) => { debug!("ifconfig ok"); } Err(e) => { error!("failed to run ifconfig: {}", e.to_string()); } } } } pub fn recv(&self, buf: &mut [u8]) -> std::io::Result { (&self.fd).read(buf) } pub fn send(&self, content: &[u8]) -> std::io::Result { (&self.fd).write(content) } } #[cfg(feature = "tap")] impl TunTapPacketHandler for Iface { async fn handle_packet_from_net(&self, data: &[u8], _: &[u8]) -> std::io::Result<()> { debug!("in tap mode, got data: {:?}", data); match self.send(data) { Err(e) => { error!("failed to write to tap: {}", e.to_string()); return Err(e); } Ok(_) => return Ok(()), } } async fn handle_packet_from_device( &self, data: &[u8], encrypt_key: &[u8], ) -> std::io::Result<()> { debug!("in tap mode2"); let edge = get_edge(); match Ethernet2Header::from_slice(data) { Ok((hdr, _)) => { let target = hdr.destination; if is_ipv6_multicast(&target) { return Ok(()); } let size = data.len(); let Ok(encrypted) = aes_encrypt(encrypt_key, data) else { error!("failed to encrypt packet request"); return Ok(()); }; let data = SdlData { is_p2p: true, network_id: edge.network_id.load(Ordering::Relaxed), ttl: SDLAN_DEFAULT_TTL as u32, src_mac: Vec::from(edge.device_config.get_mac()), dst_mac: Vec::from(target), data: Vec::from(encrypted), }; let msg = encode_to_udp_message(Some(data), PacketType::Data as u8).unwrap(); send_packet_to_net(edge, target, &msg, size as u64).await; } Err(e) => { error!("failed to parse packet from device"); } }; Ok(()) } } #[cfg(not(feature = "tap"))] impl TunTapPacketHandler for Iface { async fn handle_packet_from_net(&self, data: &[u8], key: &[u8]) -> std::io::Result<()> { debug!("in tun mode"); // got layer 2 frame match Ethernet2Header::from_slice(&data) { Ok((hdr, rest)) => { if rest.len() < 4 { error!("payload length error"); return Ok(()); } // let crc_code = &rest[(rest.len() - 4)..rest.len()]; // let rest = &rest[..(rest.len() - 4)]; // let crc_hash: crc::Crc = crc::Crc::::new(&crc::CRC_32_CKSUM); // let ck = caculate_crc(&data[..(data.len() - 4)]); // let sent_ck = u32::from_be_bytes(crc_code.try_into().unwrap()); // debug!("ck = {}, sent_ck = {}", ck, sent_ck); debug!("ip size is {}", rest.len()); let edge = get_edge(); let self_mac = edge.device_config.get_mac(); if hdr.destination != self_mac && !is_multi_broadcast(&hdr.destination) { error!( "packet to [{:?}] not direct to us", mac_to_string(&hdr.destination) ); return Ok(()); } if hdr.ether_type == ARP { let mut arp = ArpHdr::from_slice(&data); let self_ip = edge.device_config.get_ip(); println!("self_ip: {:?}", self_ip.to_be_bytes()); let from_ip = ((arp.sipaddr[0] as u32) << 16) + arp.sipaddr[1] as u32; println!("from_ip: {:?}", from_ip.to_be_bytes()); let dest_ip = ((arp.dipaddr[0] as u32) << 16) + arp.dipaddr[1] as u32; println!("dest_ip: {:?}", dest_ip.to_be_bytes()); match arp.opcode { ARP_REQUEST => { // handle ARP REQUEST debug!("got ARP REQUEST"); if arp.ethhdr.dest != [0xff; 6] { println!("ARP REQUEST not broadcast"); return Ok(()); } if dest_ip == self_ip { send_arp_request(ArpRequestInfo::Set { ip: from_ip, mac: arp.shwaddr, }) .await; // target to us arp.opcode = ARP_REPLY; arp.dhwaddr = arp.shwaddr; arp.shwaddr = self_mac; arp.ethhdr.src = self_mac; arp.ethhdr.dest = arp.dhwaddr; arp.dipaddr = arp.sipaddr; arp.sipaddr = [((self_ip >> 16) & 0xffff) as u16, (self_ip & 0xffff) as u16]; let data = arp.marshal_to_bytes(); let Ok(encrypted) = aes_encrypt(key, &data) else { error!("failed to encrypt arp reply"); return Ok(()); }; let data = SdlData { is_p2p: true, ttl: 2, network_id: edge.network_id.load(Ordering::Relaxed), src_mac: Vec::from(self_mac), dst_mac: Vec::from(arp.dhwaddr), data: encrypted, }; let v = encode_to_udp_message(Some(data), PacketType::Data as u8) .unwrap(); println!( "xxxx send arp reply to [{}], selfmac=[{}]", mac_to_string(&arp.dhwaddr), mac_to_string(&self_mac) ); send_packet_to_net(edge, arp.dhwaddr, &v, 0).await; // send_to_sock(edge, &v, from_sock); // edge.sock.send(v).await; } } ARP_REPLY => { println!("got arp reply",); println!("mac {:?} is at {:?}", arp.shwaddr, from_ip.to_be_bytes()); if dest_ip == self_ip { send_arp_request(ArpRequestInfo::Set { ip: from_ip, mac: arp.shwaddr, }) .await; } } _other => { println!("unknown arp type info"); } } } else { match IpHeaders::from_slice(rest) { Ok((iphdr, _)) => { let Some(ipv4) = iphdr.ipv4() else { error!("not ipv4, dropping"); return Ok(()); }; let ip = u32::from_be_bytes(ipv4.0.source); let mac = hdr.source; if !is_multi_broadcast(&mac) { send_arp_request(ArpRequestInfo::Set { ip, mac }).await; } } Err(e) => { error!("failed to parse ip header, dropping"); return Ok(()); } } println!("got ip packet"); println!("got data: {:?}", rest); match edge.device.send(rest) { Ok(size) => { debug!("send to tun {} bytes", size); } Err(e) => { error!("failed to send to device: {}", e.to_string()); } } // edge.tun.send_data_to_tun(Vec::from(hdr.1)).await; } } Err(e) => { error!("failed to parse tap packet: {}", e); return Ok(()); } } Ok(()) } async fn handle_packet_from_device( &self, data: &[u8], encrypt_key: &[u8], ) -> std::io::Result<()> { let eee = get_edge(); let src_mac = eee.device_config.get_mac(); match IpHeaders::from_slice(&data) { Ok((iphdr, _payload)) => { let Some(ipv4hdr) = iphdr.ipv4() else { debug!("ipv6 packet ignored"); return Ok(()); }; let dstip = u32::from_be_bytes(ipv4hdr.0.destination); debug!("packet dst ip: {:?}", ipv4hdr.0.destination); let src = u32::from_be_bytes(ipv4hdr.0.source); debug!("packet src ip: {:?}", ipv4hdr.0.source); // packet should be sent to dev debug!("got {} bytes from tun", data.len()); if (!eee.config.allow_routing) && (src != eee.device_config.get_ip()) { info!("dropping routed packet"); return Ok(()); } if !eee.is_authorized() { debug!("drop tun packet due to not authed"); return Ok(()); } match send_arp_request(ArpRequestInfo::Lookup { ip: dstip }).await { ArpResponse::LookupResp { mac, ip, do_arp_request, } => { if do_arp_request { println!( "find ip: {:?} => {:?}", src.to_be_bytes(), dstip.to_be_bytes() ); let arp_msg = generate_arp_request(src_mac, ip, eee.device_config.get_ip()); let Ok(encrypted) = aes_encrypt(&encrypt_key, &arp_msg) else { error!("failed to encrypt arp request"); return Ok(()); }; // println!("arp_msg: {:?}", arp_msg); let data = SdlData { network_id: eee.network_id.load(Ordering::Relaxed), src_mac: Vec::from(src_mac), dst_mac: Vec::from([0xff; 6]), is_p2p: true, ttl: SDLAN_DEFAULT_TTL as u32, data: encrypted, }; let data = encode_to_udp_message(Some(data), PacketType::Data as u8).unwrap(); debug!("sending arp"); // let data = marshal_message(&data); send_packet_to_net(eee, BROADCAST_MAC, &data, arp_msg.len() as u64) .await; // edge.sock.send(data).await; // println!("should send arp"); return Ok(()); } // prepend the ether header let mut etherheader = Ethernet2Header::default(); etherheader.destination = mac; etherheader.ether_type = etherparse::EtherType::IPV4; etherheader.source = src_mac; let mut packet = Vec::with_capacity(14 + data.len() + 4); packet.extend_from_slice(ðerheader.to_bytes()[..]); packet.extend_from_slice(&data); let crc = caculate_crc(&packet); packet.extend_from_slice(&crc.to_be_bytes()); let pkt_size = packet.len(); // println!("sending data with mac"); let Ok(encrypted) = aes_encrypt(&encrypt_key, &packet) else { error!("failed to encrypt packet request"); return Ok(()); }; let data = SdlData { is_p2p: true, network_id: eee.network_id.load(Ordering::Relaxed), ttl: SDLAN_DEFAULT_TTL as u32, src_mac: Vec::from(src_mac), dst_mac: Vec::from(mac), data: Vec::from(encrypted), }; let msg = encode_to_udp_message(Some(data), PacketType::Data as u8).unwrap(); let size = msg.len(); send_packet_to_net(eee, mac, &msg, pkt_size as u64).await; // let dstip = u32::from_be_bytes(ipv4hdr.0.destination); println!( "{:?} => {:?}, size={}", ipv4hdr.0.source, ipv4hdr.0.destination, size ); } _ => {} } } Err(e) => { error!("failed to parse ip packet: {}", e.to_string()); } } Ok(()) } } pub fn get_install_channel() -> String { "linux".to_owned() }