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

1028 lines
35 KiB
Rust
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#[cfg(not(feature = "tun"))]
use bytes::BytesMut;
#[cfg(feature = "tun")]
use bytes::{Bytes, BytesMut};
use etherparse::{Ethernet2Header};
use ipnet::Ipv4Net;
use sdlan_sn_rs::config::SDLAN_DEFAULT_TTL;
use sdlan_sn_rs::utils::{
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::{self, OpenOptions};
use std::net::Ipv4Addr;
use std::os::unix::fs::{MetadataExt, PermissionsExt};
use std::path::Path;
use std::ptr::null_mut;
use std::sync::atomic::Ordering;
use sdlan_sn_rs::utils::Result;
use std::io::{BufRead, BufReader, Read, Write};
use std::os::fd::AsRawFd;
use std::process::Command;
use tracing::{debug, error, info};
#[cfg(feature = "tun")]
use crate::caculate_crc;
use crate::get_edge;
#[cfg(not(feature = "tun"))]
use crate::network::{ARP_REPLY, ArpHdr, EthHdr};
use crate::network::{Node, send_packet_to_net};
#[cfg(not(feature = "tun"))]
use crate::pb::SdlArpResponse;
#[cfg(feature = "tun")]
use crate::pb::SdlArpResponse;
use crate::pb::{encode_to_udp_message, SdlData};
use crate::tcp::PacketType;
use super::device::{DeviceConfig, Mode};
use super::TunTapPacketHandler;
const RESOLV_FILE: &'static str = "/etc/resolv.conf";
const RESOLV_FILE_BACKUP: &'static str = "/etc/resolv.conf.punchnet.bak";
use crate::network::DNS_IP;
// #[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,
has_resolvectl: bool,
}
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.clear();
_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()
};
let has_resolvectl = check_has_resolvectl();
Ok(Iface { fd: fs, mode, name, has_resolvectl })
} else {
Err(SDLanError::NormalError("failed to setup tun"))
}
}
pub fn reload_config(&self, node: &Node, device_config: &DeviceConfig, network_domain: &str) {
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 mask = net_bit_len_to_mask(netbit);
let mut default_gw = (ip & mask) + 1;
if default_gw == ip {
default_gw += 1;
}
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());
}
}
node.route_table.apply_system();
if node.config.allow_routing.load(Ordering::Relaxed) {
set_allow_routing();
}
// TODO: set dns should be opened
/*
if let Err(e) = set_dns(self, &self.name, network_domain, &ip_to_string(&default_gw)) {
error!("failed to set dns: {}", e.as_str());
}
*/
} 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());
}
}
if let Err(e) = set_dns(self, &self.name, network_domain, &ip_to_string(&default_gw)) {
error!("failed to set dns: {}", e.as_str());
}
}
}
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]) -> 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: BytesMut,
// 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 {
use etherparse::EtherType;
if let Some(hdr) = eth.ethernet2() {
use bytes::Bytes;
if hdr.ether_type == EtherType::ARP {
use crate::network::{ARP_REQUEST, ArpHdr};
let arp = ArpHdr::from_slice(&data);
match arp.opcode {
ARP_REQUEST => {
let dest_ip = ((arp.dipaddr[0] as u32) << 16) + arp.dipaddr[1] as u32;
if edge.device_config.contains(&Ipv4Addr::from_bits(dest_ip)) {
let _ = edge.send_arp_request(dest_ip, dest_ip).await;
} else {
if let Some((_, real_ip)) = edge.route_table.lookup(dest_ip) {
let real_ip = u32::from_be_bytes(real_ip.octets());
let _ = edge.send_arp_request(dest_ip, real_ip).await;
}
}
/*
let request = SdlArpRequest {
pkt_id: edge.get_next_packet_id(),
target_ip: dest_ip,
};
let req = encode_to_tcp_message(Some(request), PacketType::ArpRequest as u8).unwrap();
let conn = get_quic_write_conn();
debug!("sending arp request");
let _ = conn.send(req).await;
*/
return Ok(());
}
_other => {
// just do the following logic
}
}
}
if let Some(ip) = headers.net {
match ip {
etherparse::NetHeaders::Ipv4(ipv4, _) => {
use crate::FiveTuple;
use etherparse::IpNumber;
if let Some(transport) = headers.transport {
match ipv4.protocol {
IpNumber::TCP => {
let tcp = transport.tcp().unwrap();
let out_five_tuple = FiveTuple {
src_ip: ipv4.source.into(),
dst_ip: ipv4.destination.into(),
src_port: tcp.source_port,
dst_port: tcp.destination_port,
proto: IpNumber::TCP.0,
};
edge.rule_cache.touch_packet(out_five_tuple);
// is tcp
}
IpNumber::UDP => {
let udp = transport.udp().unwrap();
let out_five_tuple = FiveTuple {
src_ip: ipv4.source.into(),
dst_ip: ipv4.destination.into(),
src_port: udp.source_port,
dst_port: udp.destination_port,
proto: IpNumber::UDP.0,
};
edge.rule_cache.touch_packet(out_five_tuple);
}
_other => {
}
}
}
if u32::from_be_bytes(ipv4.destination) == DNS_IP {
// should send to dns
if let Err(e) = edge.udp_sock_for_dns.send_to(&data[14..], format!("{}:15353", edge.server_ip)).await {
error!("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) = edge.encryptor.load().encrypt(&data) else {
// let Ok(encrypted) = edge.encryptor.read().unwrap().encrypt(&data) else {
// let Ok(encrypted) = aes_encrypt(encrypt_key, &data) else {
error!("failed to encrypt packet request");
return Ok(());
};
let data_bytes = Bytes::from(encrypted);
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: data_bytes,
identity_id: edge.identity_id.load(),
session_token: edge.session_token.get(),
};
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 {
error!("erro 2");
}
} else {
error!("erro 1");
}
Ok(())
}
}
#[cfg(feature = "tun")]
impl TunTapPacketHandler for Iface {
async fn handle_packet_from_net(&self, data: &[u8]) -> std::io::Result<()> {
debug!("in tun mode");
// got layer 2 frame
match Ethernet2Header::from_slice(&data) {
Ok((hdr, rest)) => {
use etherparse::ether_type::ARP;
use sdlan_sn_rs::utils::is_multi_broadcast;
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) {
use sdlan_sn_rs::utils::mac_to_string;
error!(
"packet to [{:?}] not direct to us",
mac_to_string(&hdr.destination)
);
return Ok(());
}
if hdr.ether_type == ARP {
use crate::network::ArpHdr;
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 {
use bytes::Bytes;
use sdlan_sn_rs::utils::mac_to_string;
use crate::network::ARP_REPLY;
edge.arp_table.set(from_ip, arp.shwaddr);
/*
use crate::network::{ARP_REPLY, ArpRequestInfo, send_arp_request};
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 {
let Ok(encrypted) = edge.encryptor.load().encrypt(&data) else {
error!("failed to encrypt arp reply");
return Ok(());
};
let data_bytes = Bytes::from(encrypted);
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: data_bytes,
session_token: edge.session_token.get(),
identity_id: edge.identity_id.load(),
};
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 {
/*
use crate::network::{ArpRequestInfo, arp_arrived, send_arp_request};
send_arp_request(ArpRequestInfo::Set {
ip: from_ip,
mac: arp.shwaddr,
})
.await;
*/
// use crate::network::arp_arrived;
edge.arp_table.set(from_ip, arp.shwaddr);
edge.arp_table.arp_arrived(from_ip, arp.shwaddr).await;
}
}
_other => {
error!("unknown arp type info");
}
}
} else {
use etherparse::IpHeaders;
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) {
//use crate::network::{ArpRequestInfo, send_arp_request};
edge.arp_table.set(ip, 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,
mut header: BytesMut,
) -> std::io::Result<()> {
use etherparse::IpHeaders;
let eee = get_edge();
let src_mac = eee.device_config.get_mac();
let data = header.split_off(14);
match IpHeaders::from_slice(&data) {
Ok((iphdr, _payload)) => {
//use crate::network::{ArpRequestInfo, ArpResponse, send_arp_request};
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.load(Ordering::Relaxed)) && (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(());
}
if dstip == DNS_IP {
// should do the dns request
// println!("request for dns");
let addr = format!("{}:15353", eee.server_ip);
// println!("send dns to {}", addr);
if let Err(e) = eee.udp_sock_for_dns.send_to(&data, &addr).await {
error!("failed to send request to 15353: {}", e);
}
return Ok(());
}
match eee.arp_table.get(dstip) {
Some(mac) => {
let pkt_size = data.len() + 14;
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);
header.copy_from_slice(&etherheader.to_bytes()[..]);
let crc = caculate_crc(&data);
header.unsplit(data);
// packet.extend_from_slice(&etherheader.to_bytes()[..]);
// packet.extend_from_slice(&data);
header.extend_from_slice(&crc.to_be_bytes());
// 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 {
let Ok(encrypted) = eee.encryptor.load().encrypt(&header) 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: Bytes::from(encrypted),
session_token: eee.session_token.get(),
identity_id: eee.identity_id.load(),
};
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;
}
None => {
header.unsplit(data);
eee.arp_table.add_to_arp_wait_list(dstip, header);
debug!(
"find ip: {:?} => {:?}",
src.to_be_bytes(),
dstip.to_be_bytes()
);
debug!("no mac found for ip {:?}, sending arp request", dstip.to_be_bytes());
// let _ = eee.send_arp_request(dstip, dstip).await;
if eee.device_config.contains(&Ipv4Addr::from_bits(dstip)) {
let _ = eee.send_arp_request(dstip, dstip).await;
} else {
if let Some((_, real_ip)) = eee.route_table.lookup(dstip) {
let real_ip = u32::from_be_bytes(real_ip.octets());
let _ = eee.send_arp_request(dstip, real_ip).await;
}
}
}
}
}
Err(e) => {
error!("failed to parse ip packet: {}", e.to_string());
}
}
Ok(())
}
}
pub fn get_install_channel() -> String {
"linux".to_owned()
}
fn check_has_resolvectl() -> bool {
let res = Command::new("resolvectl")
.arg("status")
.output();
if let Ok(_) = res {
true
} else {
false
}
}
fn add_dns_route(gw: &str) -> Result<()>{
Command::new("route")
.arg("add")
.arg("-host")
.arg("100.100.100.100")
.arg("gw")
.arg(gw)
.output()?;
Ok(())
}
fn add_resolvectl(
name: &str,
network_domain: &str,
) -> Result<()>{
Command::new("resolvectl")
.arg("dns")
.arg(name)
.arg("100.100.100.100")
.output()?;
Command::new("resolvectl")
.arg("domain")
.arg(name)
.arg(format!("~{}", network_domain))
.output()?;
Ok(())
}
fn set_dns(
iface: &Iface,
name: &str,
network_domain: &str,
gw: &str
) -> Result<()> {
if iface.has_resolvectl {
add_resolvectl(name, network_domain)?;
} else {
backup_resolv_conf()?;
modify_resolv_conf(&vec!["100.100.100.100".to_owned()], network_domain, true)?;
}
add_dns_route(gw)?;
Ok(())
}
pub fn restore_dns() -> Result<()> {
let eee = get_edge();
if !eee.device.has_resolvectl {
// should restore /etc/resolv.conf
restore_resolv_conf()?;
}
Ok(())
}
/// 修改 /etc/resolv.conf 中的 nameserver 条目
///
/// - `new_nameservers`: 新的 nameserver 列表IPv4/IPv6 字符串)
/// - `keep_other_ns`: 是否保留原有的 nameservertrue = 追加到新列表后false = 完全替换)
pub fn modify_resolv_conf(new_nameservers: &[String], search_domain: &str, keep_other_ns: bool) -> Result<()> {
let path = Path::new(RESOLV_FILE);
if !path.exists() {
return Err(SDLanError::IOError(format!("{} does not exists", RESOLV_FILE)));
}
// 读取原文件权限和元数据
let metadata = fs::metadata(path)?;
let perms = fs::Permissions::from_mode(metadata.mode());
let uid = metadata.uid();
let gid = metadata.gid();
// 读取所有行
let file = fs::File::open(path)?;
let reader = BufReader::new(file);
let mut lines = Vec::new();
let mut inserted = false;
let mut encounted_nameserver = false;
let mut search_added = false;
for line in reader.lines() {
let line = line?;
let trimmed = line.trim();
if trimmed.starts_with("nameserver ") {
// 提取 IP
encounted_nameserver = true;
if keep_other_ns {
lines.push(line);
}
// 如果不保留原有 nameserver就不加入 lines
} else {
if encounted_nameserver {
if !inserted {
inserted = true;
for new in new_nameservers {
lines.push(format!("nameserver {}", new.clone()));
}
}
}
// 保留非 nameserver 行注释、search、options 等)
if trimmed.starts_with("search ") {
lines.push(format!("{} {}", trimmed, search_domain));
search_added = true;
} else {
lines.push(line);
}
}
}
if !search_added {
lines.push(format!("search {}", search_domain));
}
// 原子写入:先写临时文件
let tmp_dir = Path::new("/etc");
let tmp_path = tmp_dir.join("resolv.conf.tmp");
let mut tmp_file = fs::File::create(&tmp_path)?;
for l in &lines {
writeln!(tmp_file, "{}", l)?;
}
tmp_file.flush()?;
// 设置权限
fs::set_permissions(&tmp_path, perms)?;
#[cfg(unix)]
{
use std::os::unix::fs::chown;
chown(&tmp_path, Some(uid), Some(gid))?;
}
// 原子替换
fs::rename(&tmp_path, path)?;
Ok(())
}
/// 备份 /etc/resolv.conf 到指定路径
fn backup_resolv_conf() -> Result<()> {
let src = Path::new(RESOLV_FILE);
let dst = Path::new(RESOLV_FILE_BACKUP);
if !src.exists() {
return Err(SDLanError::IOError(format!("{} does not exists", RESOLV_FILE)));
// anyhow::bail!("Source /etc/resolv.conf does not exist");
}
// 如果目标已存在,可选择覆盖或跳过(这里覆盖)
if dst.exists() {
fs::remove_file(dst)?;
}
fs::copy(src, dst)?;
// 保留原权限
let metadata = fs::metadata(src)?;
let permissions = fs::Permissions::from_mode(metadata.mode());
fs::set_permissions(dst, permissions)?;
// 保留所有者(需要 root 权限,否则会失败)
#[cfg(unix)]
{
use std::os::unix::fs::chown;
let uid = metadata.uid();
let gid = metadata.gid();
chown(dst, Some(uid), Some(gid))?;
}
Ok(())
}
/// 从备份路径恢复 /etc/resolv.conf
fn restore_resolv_conf() -> Result<()> {
let src = Path::new(RESOLV_FILE_BACKUP);
let dst = Path::new(RESOLV_FILE);
if !src.exists() {
return Err(SDLanError::IOError(format!("{} does not exists", RESOLV_FILE_BACKUP)));
}
// 如果目标是符号链接,先删除链接再复制(避免写入到链接指向位置)
if dst.is_symlink() {
fs::remove_file(dst)?;
} else if dst.exists() {
fs::remove_file(dst)?;
}
fs::copy(src, dst)?;
// 保留备份文件的权限
let metadata = fs::metadata(src)?;
let permissions = fs::Permissions::from_mode(metadata.mode());
fs::set_permissions(dst, permissions)?;
#[cfg(unix)]
{
use std::os::unix::fs::chown;
let uid = metadata.uid();
let gid = metadata.gid();
chown(dst, Some(uid), Some(gid))?;
}
Ok(())
}
pub fn del_route(net: &Ipv4Net, gw: &Ipv4Addr) -> Result<()> {
let res = Command::new("route")
.arg("del")
.arg("-net")
.arg(net.to_string())
.arg("gw")
.arg(gw.to_string())
.output()?;
Ok(())
}
pub fn add_route(net: &Ipv4Net, gw: &Ipv4Addr) -> Result<()> {
let res = Command::new("route")
.arg("add")
.arg("-net")
.arg(net.to_string())
.arg("gw")
.arg(gw.to_string())
.output()?;
Ok(())
}
pub fn set_disallow_routing() {
let _ = Command::new("sysctl")
.arg("-w")
.arg("net.ipv4.ip_forward=0")
.output();
let _ = Command::new("iptables")
.arg("-t")
.arg("nat")
.arg("-D")
.arg("POSTROUTING")
.arg("-j")
.arg("MASQUERADE")
.output();
}
pub fn set_allow_routing() {
let _ = Command::new("sysctl")
.arg("-w")
.arg("net.ipv4.ip_forward=1")
.output();
let _ = Command::new("iptables")
.arg("-t")
.arg("nat")
.arg("-D")
.arg("POSTROUTING")
.arg("-j")
.arg("MASQUERADE")
.output();
let _ = Command::new("iptables")
.arg("-t")
.arg("nat")
.arg("-A")
.arg("POSTROUTING")
.arg("-j")
.arg("MASQUERADE")
.output();
}
#[cfg(feature = "tun")]
pub async fn arp_reply_arrived(edge: &Node, data: SdlArpResponse) {
debug!("got arp response: {:?}", data);
if data.target_mac.len() != 6 {
// invalid target_mac
error!("invalid target_mac: {:?}, ip={}", data.target_mac, ip_to_string(&data.target_ip));
return;
}
let ip = data.target_ip;
let mac = data.target_mac.try_into().unwrap();
edge.arp_table.arp_arrived(ip, mac).await;
}
#[cfg(not(feature = "tun"))]
pub async fn arp_reply_arrived(edge: &Node, data: SdlArpResponse) {
debug!("got arp response: {:?}", data);
if data.target_mac.len() != 6 {
// invalid target_mac
error!("invalid target_mac: {:?}, ip={}", data.target_mac, ip_to_string(&data.target_ip));
return;
}
// TODO: construct the arp reply, and write to tun;
let src_mac = data.target_mac.try_into().unwrap();
let dst_mac = edge.device_config.get_mac();
let dst_ip = edge.device_config.get_ip();
let src_ip = data.origin_ip;
let hdr = ArpHdr{
ethhdr: EthHdr {
dest: dst_mac,
src: src_mac,
eth_type: 0x0806,
},
hwtype: 0x0001,
protocol: 0x0800,
hwlen: 6,
protolen: 4,
opcode: ARP_REPLY,
shwaddr: src_mac,
sipaddr: [((src_ip >> 16) as u16) & 0xffff, (src_ip as u16) & 0xffff],
dhwaddr: dst_mac,
dipaddr: [((dst_ip >> 16) & 0x0000ffff) as u16, (dst_ip & 0x0000ffff) as u16]
};
let data = hdr.marshal_to_bytes();
if let Err(_e) = edge.device.send(&data) {
error!("failed to write arp response to device");
}
}