sdlan-lib-rs/src/network/tun_linux.rs

522 lines
20 KiB
Rust
Executable File

use etherparse::{Ethernet2Header};
use sdlan_sn_rs::config::SDLAN_DEFAULT_TTL;
use sdlan_sn_rs::utils::{
aes_encrypt, ip_to_string, is_ipv6_multicast, net_bit_len_to_mask,
SDLanError,
};
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;
use tracing::{debug, error, info};
use crate::get_edge;
use crate::network::send_packet_to_net;
use crate::pb::{encode_to_udp_message, SdlData};
use crate::tcp::PacketType;
use super::device::{DeviceConfig, Mode};
use super::TunTapPacketHandler;
const DNS_IP: u32 = (100<<24) + (100<<16) + (100<<8) + 100;
// #[link(name = "tuntap", kind="static")]
#[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<Self> {
Iface::open_tun(ifname, mode, true)
}
pub fn without_packet_info(ifname: &str, mode: Mode) -> Result<Self> {
Iface::open_tun(ifname, mode, false)
}
fn open_tun(ifname: &str, mode: Mode, need_packet_info: bool) -> Result<Self> {
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!(not(feature = "tun")) {
info!("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("mtu")
.arg(format!("{}", device_config.mtu))
.arg("up")
.output();
match res {
Ok(_) => {
debug!("ifconfig ok");
}
Err(e) => {
error!("failed to run ifconfig: {}", e.to_string());
}
}
} else {
info!("set tun device");
let res = Command::new("ifconfig")
.arg(&self.name)
.arg(ip)
.arg("netmask")
.arg(&netbit)
.arg("mtu")
.arg(format!("{}", device_config.mtu))
.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<usize> {
(&self.fd).read(buf)
}
pub fn send(&self, content: &[u8]) -> std::io::Result<usize> {
(&self.fd).write(content)
}
}
#[cfg(not(feature = "tun"))]
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: Vec<u8>,
encrypt_key: &[u8],
) -> std::io::Result<()> {
use etherparse::PacketHeaders;
debug!("in tap mode2");
let edge = get_edge();
let Ok(headers) = PacketHeaders::from_ethernet_slice(&data) else {
error!("failed to parse packet");
return Ok(());
};
if let Some(eth) = headers.link {
if let Some(hdr) = eth.ethernet2() {
if let Some(ip) = headers.net {
match ip {
etherparse::NetHeaders::Ipv4(ipv4, _) => {
println!("3, target = {}.{}.{}.{}", ipv4.destination[0], ipv4.destination[1], ipv4.destination[2], ipv4.destination[3]);
if u32::from_be_bytes(ipv4.destination) == DNS_IP {
// should send to dns
println!("got dns request");
if let Err(e) = edge.udp_sock_for_dns.send_to(&data[14..], format!("{}:15353", edge.server_ip)).await {
println!("failed to send request to 15353: {}", e);
}
// edge.udp_sock_for_dns.send_to()
return Ok(())
}
}
_other => {
// just ignore
}
}
}
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;
} else {
println!("erro 2");
}
} else {
println!("erro 1");
}
Ok(())
}
}
#[cfg(feature = "tun")]
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<u32> = crc::Crc::<u32>::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] {
debug!("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();
debug!(
"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 => {
debug!("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;
arp_arrived(from_ip, arp.shwaddr).await;
}
}
_other => {
error!("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(_) => {
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 tun packet: {}", e);
return Ok(());
}
}
Ok(())
}
async fn handle_packet_from_device(
&self,
data: Vec<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 {
add_to_arp_wait_list(dstip, data);
debug!(
"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(&etherheader.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);
}
_ => {}
}
}
Err(e) => {
error!("failed to parse ip packet: {}", e.to_string());
}
}
Ok(())
}
}
pub fn get_install_channel() -> String {
"linux".to_owned()
}