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

896 lines
33 KiB
Rust
Executable File

use bytes::{Bytes, BytesMut};
use etherparse::ether_type::ARP;
use etherparse::{Ethernet2Header, IpHeaders, NetSlice, SlicedPacket, TransportSlice};
use ipnet::Ipv4Net;
use sdlan_sn_rs::config::SDLAN_DEFAULT_TTL;
use sdlan_sn_rs::utils::{
aes_encrypt, ip_to_string, is_multi_broadcast, net_bit_len_to_mask, Result, SDLanError,
BROADCAST_MAC,
};
use std::io::{Error, ErrorKind};
use std::net::Ipv4Addr;
use std::os::windows::process::CommandExt;
use std::process::{Command, Stdio};
use std::sync::atomic::Ordering;
use std::sync::Arc;
use tracing::{debug, error, info};
use tun_rs::{AsyncDevice, SyncDevice};
use wintun;
use crate::network::{
form_ethernet_packet, generate_arp_request, parse_dns_payload, send_packet_to_net, ArpHdr,
Node, ARP_REPLY, ARP_REQUEST, DNS_IP, LAYER,
};
use crate::pb::{encode_to_udp_message, SdlArpResponse, SdlData};
use crate::tcp::PacketType;
use crate::utils::mac_to_string;
use crate::{caculate_crc, get_edge};
use super::device::{DeviceConfig, Mode};
use super::TunTapPacketHandler;
pub struct Iface {
device: AsyncDevice,
if_idx: u32,
name: String,
}
impl Iface {
fn new(_path: &str, name: &str) -> Self {
println!("layer = {:?}", LAYER);
let dev = tun_rs::DeviceBuilder::new()
// .wintun_file(path.to_string())
.name(name)
// .ipv4(Ipv4Addr::new(10, 10, 4, 39), Ipv4Addr::new(255, 255, 255, 0), None)
.layer(tun_rs::Layer::L3)
.mtu(1280)
// .enable(true)
.build_async()
.expect("failed to create tun");
let idx = dev.if_index().expect("failed to get if index");
println!("index = {}", idx);
Self {
device: dev,
if_idx: idx,
name: name.to_string(),
}
}
}
impl Iface {
pub fn get_if_idx(&self) -> u32 {
self.if_idx
}
pub async fn recv(&self, buf: &mut [u8]) -> std::io::Result<usize> {
self.device.recv(buf).await
}
pub async fn send(&self, content: &[u8]) -> std::io::Result<usize> {
self.device.send(content).await
}
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 ip = ip_to_string(&ip);
let netbit = ip_to_string(&net_bit_len_to_mask(netbit));
let mut cmd = Command::new("netsh");
debug!("name={}, addr={}, mask={}", self.name, ip, netbit);
let command = cmd
.creation_flags(0x08000000)
.arg("interface")
.arg("ip")
.arg("set")
.arg("address")
.arg(&format!("name=\"{}\"", self.name))
.arg("source=static")
.arg(&format!("addr={}", ip))
.arg(&format!("mask={}", netbit));
let res = command.status();
// let res = command.output();
match res {
Ok(r) => {
if r.success() {
debug!("netsh ok");
} else {
error!("failed to run netsh, returned {:?}", r.code())
}
}
Err(e) => {
error!("failed to run netsh: {}", e.to_string());
}
}
let mut cmd = Command::new("netsh");
let command = cmd
.creation_flags(0x08000000)
.arg("interface")
.arg("ipv4")
.arg("set")
.arg("subinterface")
.arg(&format!("\"{}\"", self.name))
.arg(format!("mtu={}", device_config.mtu))
.arg("store=persistent");
let res = command.status();
match res {
Ok(r) => {
if r.success() {
debug!("netsh2 ok");
} else {
error!("failed to run netsh set mtu, returned {:?}", r.code())
}
}
Err(e) => {
error!("failed to run netsh2: {}", e.to_string());
}
}
// let gw = ip_to_string(&default_gw);
// debug!("gw = {}", ip);
if let Err(e) = set_dns(&self.name, network_domain, &ip, self.if_idx) {
error!("failed to set dns: {:?}", e);
} else {
debug!("set dns ok");
}
node.route_table.apply_system(self.if_idx);
}
}
pub struct IfaceOld {
if_idx: u32,
name: String,
_adapter: Arc<wintun::Adapter>,
session: Arc<wintun::Session>,
}
impl IfaceOld {
pub fn get_if_idx(&self) -> u32 {
self.if_idx
}
pub fn recv(&self, buf: &mut [u8]) -> std::io::Result<usize> {
let Ok(pkt) = self.session.receive_blocking() else {
return Err(Error::new(ErrorKind::Other, "failed to receive"));
};
let content = pkt.bytes();
let length = content.len();
if content.len() > buf.len() {
return Err(Error::new(ErrorKind::Other, "length not enough"));
}
for i in 0..content.len() {
buf[i] = content[i];
}
Ok(length)
}
pub fn send(&self, content: &[u8]) -> std::io::Result<usize> {
let Ok(mut pkt) = self.session.allocate_send_packet(content.len() as u16) else {
error!("failed to allocate send packet");
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
"failed to allocate send packet",
));
};
let buf: &mut [u8] = pkt.bytes_mut();
buf.copy_from_slice(content);
self.session.send_packet(pkt);
Ok(content.len())
}
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 ip = ip_to_string(&ip);
let netbit = ip_to_string(&net_bit_len_to_mask(netbit));
let mut cmd = Command::new("netsh");
debug!("name={}, addr={}, mask={}", self.name, ip, netbit);
let command = cmd
.creation_flags(0x08000000)
.arg("interface")
.arg("ip")
.arg("set")
.arg("address")
.arg(&format!("name=\"{}\"", self.name))
.arg("source=static")
.arg(&format!("addr={}", ip))
.arg(&format!("mask={}", netbit));
let res = command.status();
// let res = command.output();
match res {
Ok(r) => {
if r.success() {
debug!("netsh ok");
} else {
error!("failed to run netsh, returned {:?}", r.code())
}
}
Err(e) => {
error!("failed to run netsh: {}", e.to_string());
}
}
let mut cmd = Command::new("netsh");
let command = cmd
.creation_flags(0x08000000)
.arg("interface")
.arg("ipv4")
.arg("set")
.arg("subinterface")
.arg(&format!("\"{}\"", self.name))
.arg(format!("mtu={}", device_config.mtu))
.arg("store=persistent");
let res = command.status();
match res {
Ok(r) => {
if r.success() {
debug!("netsh2 ok");
} else {
error!("failed to run netsh set mtu, returned {:?}", r.code())
}
}
Err(e) => {
error!("failed to run netsh2: {}", e.to_string());
}
}
// let gw = ip_to_string(&default_gw);
// debug!("gw = {}", ip);
if let Err(e) = set_dns(&self.name, network_domain, &ip, self.if_idx) {
error!("failed to set dns: {:?}", e);
} else {
debug!("set dns ok");
}
node.route_table.apply_system(self.if_idx);
}
}
impl TunTapPacketHandler for Iface {
async fn handle_packet_from_net(&self, data: &[u8]) -> std::io::Result<()> {
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 mut data_buf = BytesMut::from(arp.marshal_to_bytes().as_slice());
let encryptor = edge.encryptor.load();
if let Err(e) = encryptor.encrypt(&mut data_buf) {
error!("failed to encrypt arp reply: {:?}", e);
return Ok(());
}
let data_bytes = data_buf.freeze();
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).await {
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<()> {
let eee = get_edge();
let src_mac = eee.device_config.get_mac();
let data = header.split_off(14);
let Ok(sliced_packet) = SlicedPacket::from_ip(&data) else {
error!("failed to parse ip packet");
return Ok(());
};
let Some(net) = sliced_packet.net else {
error!("failed to get ip packet");
return Ok(());
};
match net {
NetSlice::Ipv4(ipv4) => {
let dstip = u32::from_be_bytes(ipv4.header().destination());
// let dstip = u32::from_be_bytes(ipv4hdr.0.destination);
debug!("packet dst ip: {:?}", ip_to_string(&dstip));
let src = u32::from_be_bytes(ipv4.header().source());
//let src = u32::from_be_bytes(ipv4hdr.0.source);
debug!("packet src ip: {:?}", ip_to_string(&src));
// 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 let Some(transport) = sliced_packet.transport {
match transport {
TransportSlice::Tcp(tcp) => {
use crate::FiveTuple;
use std::net::IpAddr;
let out_five_tuple = FiveTuple {
src_ip: IpAddr::V4(ipv4.header().source_addr()),
dst_ip: IpAddr::V4(ipv4.header().destination_addr()),
src_port: tcp.source_port(),
dst_port: tcp.destination_port(),
proto: etherparse::IpNumber::TCP.0,
};
eee.rule_cache.touch_packet(out_five_tuple);
}
TransportSlice::Udp(udp) => {
if dstip == DNS_IP {
// should do the dns request
// println!("request for dns");
parse_dns_payload(
eee,
udp.payload(),
&data,
src,
udp.source_port(),
)
.await;
// edge.udp_sock_for_dns.send_to()
return Ok(());
} else {
use crate::FiveTuple;
use std::net::IpAddr;
let out_five_tuple = FiveTuple {
src_ip: IpAddr::V4(ipv4.header().source_addr()),
dst_ip: IpAddr::V4(ipv4.header().destination_addr()),
src_port: udp.source_port(),
dst_port: udp.destination_port(),
proto: etherparse::IpNumber::UDP.0,
};
eee.rule_cache.touch_packet(out_five_tuple);
}
}
_other => {}
}
}
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 encryptor = eee.encryptor.load();
if let Err(e) = encryptor.encrypt(&mut header) {
error!("failed to encrypt packet request: {:?}", e);
return Ok(());
}
let data_bytes = header.freeze();
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: data_bytes,
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);
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)) {
debug!("contains dst ip {}", ip_to_string(&dstip));
eee.arp_table.add_to_arp_wait_list(dstip, header);
let _ = eee.send_arp_request(dstip, dstip).await;
} else {
debug!("try to lookup ip: {}", ip_to_string(&dstip));
if let Some((_, real_ip)) = eee.route_table.lookup(dstip) {
eee.arp_table.add_to_arp_wait_list(
u32::from_be_bytes(real_ip.octets()),
header,
);
error!("got target route: {}", real_ip);
let real_ip = u32::from_be_bytes(real_ip.octets());
let _ = eee.send_arp_request(real_ip, dstip).await;
}
}
}
}
}
NetSlice::Ipv6(ipv6) => {}
}
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);
debug!("got {} bytes from tun", data.len());
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(())
}*/
}
fn create_wintun(path: &str, name: &str) -> std::io::Result<Iface> {
Ok(Iface::new(path, name))
/*
let wt = unsafe { wintun::load_from_path(path) }.expect("failed to load wintun");
let adapter = match wintun::Adapter::open(&wt, name) {
Ok(a) => a,
Err(_e) => {
let Ok(adapt) = wintun::Adapter::create(&wt, name, "Punchnet", None) else {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
"failed to create Punch adapter",
));
};
adapt
}
};
let idx = adapter
.get_adapter_index()
.expect("failed to get adapter index");
// println!("idx = {}", idx);
let Ok(sess) = adapter.start_session(wintun::MAX_RING_CAPACITY) else {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
"failed to start session, maybe one process is running, or not running with admin?",
));
};
let session = Arc::new(sess);
Ok(Iface {
if_idx: idx,
_adapter: adapter,
session,
name: name.to_owned(),
})
*/
}
pub fn new_iface(name: &str) -> std::io::Result<Iface> {
create_wintun("wintun.dll", name)
// Ok(Box::new(create_wintun("/path/to/file")))
}
pub fn get_install_channel() -> String {
"windows".to_owned()
}
pub fn set_dns(name: &str, _network_domain: &str, gw: &str, ifidx: u32) -> Result<()> {
let res = Command::new("ROUTE")
.arg("ADD")
.arg("100.100.100.100")
.arg("MASK")
.arg("255.255.255.255")
.arg(gw)
.arg("IF")
.arg(ifidx.to_string())
.creation_flags(0x08000000)
.status()?;
if !res.success() {
error!(
"failed to add route for dns 100.100.100.100: {:?}",
res.code()
);
return Err(SDLanError::IOError(
"failed to add route for dns".to_owned(),
));
}
//println!("res1: {}", res.status.success());
debug!("route set ok");
let res = Command::new("netsh")
.arg("dnsclient")
.arg("set")
.arg("dnsserver")
.arg(&format!("name={}", name))
.arg("source=static")
.arg("address=100.100.100.100")
.arg("validate=no")
.creation_flags(0x08000000)
.status()?;
if !res.success() {
error!("failed to set dnsserver");
return Err(SDLanError::IOError("failed to add dnsserver".to_owned()));
}
// println!("res2: {}", res.status.success());
debug!("netsh set ok");
Ok(())
}
pub fn restore_dns(take_over_dns: bool) {}
pub fn del_route(net: &Ipv4Net, gw: &Ipv4Addr) -> Result<()> {
error!("deleting route: {} gw {}", net, gw);
let mask = net.netmask().to_string();
let network = net.network().to_string();
let res = Command::new("route")
.arg("delete")
.arg(network)
.arg("MASK")
.arg(mask)
.arg(gw.to_string())
.status()?;
if !res.success() {
error!("failed to set dnsserver");
return Err(SDLanError::IOError("failed to delete route".to_owned()));
}
Ok(())
}
pub fn add_route(net: &Ipv4Net, gw: &Ipv4Addr, if_idx: u32) -> Result<()> {
let mask = net.netmask().to_string();
let network = net.network().to_string();
let result = Command::new("route")
.arg("add")
.arg(network)
.arg("MASK")
.arg(mask)
.arg(gw.to_string())
.arg("if")
.arg(format!("{}", if_idx))
.status()?;
if !result.success() {
error!("failed to add route: {:?}", result.code());
return Err(SDLanError::IOError("failed to add route".to_owned()));
}
Ok(())
}
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.origin_ip;
let mac = data.target_mac.try_into().unwrap();
debug!("setting mac {:?} for {}", mac, ip_to_string(&ip));
edge.arp_table.set(ip, mac);
edge.arp_table.arp_arrived(ip, mac).await;
}