468 lines
18 KiB
Rust
Executable File
468 lines
18 KiB
Rust
Executable File
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_multi_broadcast, net_bit_len_to_mask, BROADCAST_MAC,
|
|
};
|
|
use std::io::{Error, ErrorKind};
|
|
use std::os::windows::process::CommandExt;
|
|
use std::process::Command;
|
|
use std::sync::atomic::Ordering;
|
|
use std::sync::Arc;
|
|
use tracing::{debug, error, info};
|
|
use wintun;
|
|
|
|
use crate::get_edge;
|
|
use crate::network::{
|
|
ARP_REPLY, ARP_REQUEST, ArpHdr, ArpRequestInfo, ArpResponse, DNS_IP, add_to_arp_wait_list, arp_arrived, form_ethernet_packet, generate_arp_request, send_arp_request, send_packet_to_net
|
|
};
|
|
use crate::pb::{encode_to_udp_message, SdlData};
|
|
use crate::tcp::PacketType;
|
|
use crate::utils::mac_to_string;
|
|
|
|
use super::device::{DeviceConfig, Mode};
|
|
use super::TunTapPacketHandler;
|
|
|
|
pub struct Iface {
|
|
if_idx: u32,
|
|
name: String,
|
|
_adapter: Arc<wintun::Adapter>,
|
|
session: Arc<wintun::Session>,
|
|
}
|
|
|
|
impl Iface {
|
|
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 mut pkt = self
|
|
.session
|
|
.allocate_send_packet(content.len() as u16)
|
|
.unwrap();
|
|
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, 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));
|
|
|
|
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.output();
|
|
|
|
match res {
|
|
Ok(r) => {
|
|
debug!("netsh ok: [{:?}]", String::from_utf8_lossy(&r.stdout));
|
|
}
|
|
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.output();
|
|
|
|
match res {
|
|
Ok(r) => {
|
|
debug!("netsh2 ok: [{:?}]", String::from_utf8_lossy(&r.stdout));
|
|
}
|
|
Err(e) => {
|
|
error!("failed to run netsh2: {}", e.to_string());
|
|
}
|
|
}
|
|
|
|
let gw = ip_to_string(&default_gw);
|
|
println!("gw = {}", gw);
|
|
if let Err(e) = set_dns(&self.name, network_domain, &gw, self.if_idx) {
|
|
println!("failed to set dns: {:?}", e);
|
|
} else {
|
|
println!("set dns ok");
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
impl TunTapPacketHandler for Iface {
|
|
async fn handle_packet_from_net(&self, data: &[u8], key: &[u8]) -> std::io::Result<()> {
|
|
// 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 = CRC_HASH.checksum(&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 && hdr.destination != BROADCAST_MAC {
|
|
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();
|
|
|
|
debug!("self_ip: {:?}", self_ip.to_be_bytes());
|
|
let from_ip = ((arp.sipaddr[0] as u32) << 16) + arp.sipaddr[1] as u32;
|
|
debug!("from_ip: {:?}", from_ip.to_be_bytes());
|
|
let dest_ip = ((arp.dipaddr[0] as u32) << 16) + arp.dipaddr[1] as u32;
|
|
debug!("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(());
|
|
}
|
|
}
|
|
|
|
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: 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(());
|
|
}
|
|
if dstip == DNS_IP {
|
|
// 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 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);
|
|
|
|
info!(
|
|
"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(());
|
|
}
|
|
|
|
let packet = form_ethernet_packet(src_mac, mac, &data);
|
|
// 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 = CRC_HASH.checksum(&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(())
|
|
}
|
|
}
|
|
|
|
fn create_wintun(path: &str, name: &str) -> Iface {
|
|
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) => wintun::Adapter::create(&wt, name, "Example", None)
|
|
.expect("failed to create tun adapter"),
|
|
};
|
|
let idx = adapter.get_adapter_index().expect("failed to get adapter index");
|
|
println!("idx = {}", idx);
|
|
let session = Arc::new(adapter.start_session(wintun::MAX_RING_CAPACITY).unwrap());
|
|
Iface {
|
|
if_idx: idx,
|
|
_adapter: adapter,
|
|
session,
|
|
name: name.to_owned(),
|
|
}
|
|
}
|
|
|
|
pub fn new_iface(name: &str, _mode: Mode) -> 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) -> std::io::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)
|
|
.output()?;
|
|
|
|
println!("res1: {}", res.status.success());
|
|
|
|
println!("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)
|
|
.output()?;
|
|
println!("res2: {}", res.status.success());
|
|
|
|
println!("netsh set ok");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn restore_dns() {
|
|
|
|
} |