570 lines
16 KiB
Rust
Executable File

#![allow(unused)]
use std::{
collections::HashMap,
sync::{Arc, atomic::{AtomicU8, Ordering}},
time::{Duration, Instant},
};
use bytes::{Bytes, BytesMut};
use dashmap::DashMap;
use tracing::{debug, error};
use once_cell::sync::OnceCell;
use sdlan_sn_rs::{config::SDLAN_DEFAULT_TTL, utils::{BROADCAST_MAC, MULTICAST_MAC, Mac, get_current_timestamp, ip_to_string, mac_to_string, net_bit_len_to_mask}};
use tokio::sync::{
mpsc::{channel, Receiver, Sender},
oneshot,
};
use crate::{network::{form_ethernet_packet, send_packet_to_net}, pb::{SdlData, encode_to_udp_message}, tcp::PacketType};
use super::{get_edge};
/*
static GLOBAL_ARP: OnceCell<ArpActor> = OnceCell::new();
pub fn init_arp() {
init_arp_wait_list();
let actor = ArpActor::new();
GLOBAL_ARP.set(actor).unwrap();
}
pub fn get_arp() -> &'static ArpActor {
GLOBAL_ARP.get().unwrap()
}
*/
const ETHER_TYPE_ARP: u16 = 0x0806;
const ETHER_TYPE_IP: u16 = 0x0800;
#[allow(unused)]
const ETHER_TYPE_IP6: u16 = 0x86dd;
const ARP_MAX_AGE: u8 = 128;
const ARP_HWTYPE_ETH: u16 = 1;
pub const ARP_REQUEST: u16 = 1;
pub const ARP_REPLY: u16 = 2;
#[repr(C)]
pub struct EthHdr {
pub dest: [u8; 6],
pub src: [u8; 6],
pub eth_type: u16,
}
#[repr(C)]
pub struct ArpHdr {
pub ethhdr: EthHdr,
pub hwtype: u16,
pub protocol: u16,
pub hwlen: u8,
pub protolen: u8,
pub opcode: u16,
pub shwaddr: [u8; 6],
pub sipaddr: [u16; 2],
pub dhwaddr: [u8; 6],
pub dipaddr: [u16; 2],
}
impl ArpHdr {
pub fn from_slice(data: &[u8]) -> Self {
if data.len() < 42 {
panic!("data size error");
}
Self {
ethhdr: EthHdr {
dest: data[0..6].try_into().unwrap(),
src: data[6..12].try_into().unwrap(),
eth_type: u16::from_be_bytes(data[12..14].try_into().unwrap()),
},
hwtype: u16::from_be_bytes(data[14..16].try_into().unwrap()),
protocol: u16::from_be_bytes(data[16..18].try_into().unwrap()),
hwlen: data[18],
protolen: data[19],
opcode: u16::from_be_bytes(data[20..22].try_into().unwrap()),
shwaddr: data[22..28].try_into().unwrap(),
sipaddr: [
u16::from_be_bytes(data[28..30].try_into().unwrap()),
u16::from_be_bytes(data[30..32].try_into().unwrap()),
],
dhwaddr: data[32..38].try_into().unwrap(),
dipaddr: [
u16::from_be_bytes(data[38..40].try_into().unwrap()),
u16::from_be_bytes(data[40..42].try_into().unwrap()),
],
}
}
pub fn marshal_to_bytes(&self) -> Vec<u8> {
let mut result = Vec::with_capacity(64);
result.extend_from_slice(&self.ethhdr.dest);
result.extend_from_slice(&self.ethhdr.src);
result.extend_from_slice(&self.ethhdr.eth_type.to_be_bytes());
result.extend_from_slice(&self.hwtype.to_be_bytes());
result.extend_from_slice(&self.protocol.to_be_bytes());
result.push(self.hwlen);
result.push(self.protolen);
result.extend_from_slice(&self.opcode.to_be_bytes());
result.extend_from_slice(&self.shwaddr);
result.extend_from_slice(&self.sipaddr[0].to_be_bytes());
result.extend_from_slice(&self.sipaddr[1].to_be_bytes());
result.extend_from_slice(&self.dhwaddr);
result.extend_from_slice(&self.dipaddr[0].to_be_bytes());
result.extend_from_slice(&self.dipaddr[1].to_be_bytes());
// result.extend_from_slice(&[0; 18]);
// let crc = CRC_HASH.checksum(&result).to_be_bytes();
// result.extend_from_slice(&crc);
result
}
pub fn new() -> Self {
Self {
ethhdr: EthHdr {
dest: [0; 6],
src: [0; 6],
eth_type: ETHER_TYPE_ARP,
},
hwtype: ARP_HWTYPE_ETH,
protocol: ETHER_TYPE_IP,
hwlen: 6,
protolen: 4,
opcode: ARP_REQUEST,
shwaddr: [0; 6],
sipaddr: [0; 2],
dhwaddr: [0; 6],
dipaddr: [0; 2],
}
}
}
// const ARP_TABLE_SIZE: usize = 8;
static ARPTIME: AtomicU8 = AtomicU8::new(0);
const BROADCAST_IPADDR: u32 = 0xffffffff;
#[derive(Debug)]
#[allow(unused)]
pub struct ArpEntry {
// ip_addr: u32,
last_seen: Instant,
hw_addr: Mac,
}
/*
impl ArpEntry {
pub fn new() -> Self {
Self {
ip_addr: 0,
arptime: 0,
hw_addr: [0; 6],
}
}
}
*/
pub struct ArpTable {
entries: Arc<DashMap<u32, ArpEntry>>,
ttl: Duration,
pending_packet_buffer: ArpWaitList,
}
impl ArpTable {
pub fn new() -> Self {
let entries = Arc::new(DashMap::new());
let res = Self {
entries: entries.clone(),
ttl: Duration::from_secs(60),
pending_packet_buffer: ArpWaitList::new(),
};
let mut bytes = BytesMut::with_capacity(1024+20);
let ttl = res.ttl;
tokio::spawn(async move {
loop {
tokio::time::sleep(Duration::from_secs(30)).await;
let now = Instant::now();
entries.retain(|_, entry| now.duration_since(entry.last_seen) < ttl);
}
});
res
}
pub async fn arp_arrived(&self, ip: u32, mac: Mac) {
self.pending_packet_buffer.arp_arrived(ip, mac).await;
}
pub fn add_to_arp_wait_list(&self, ip: u32, origin_data: BytesMut) {
self.pending_packet_buffer.add_to_wait_list(ip, origin_data);
}
#[inline]
pub fn get(&self, ip: u32) -> Option<Mac> {
self.entries.get(&ip).map(|entry| entry.hw_addr)
}
pub fn set(&self, ip: u32, mac: Mac) {
self.entries.insert(
ip,
ArpEntry {
last_seen: Instant::now(),
hw_addr: mac,
},
);
}
}
/*
pub struct ArpInfo {
// host_ip: AtomicU32,
// ip representation of mask
// host_netmask: AtomicU32,
entry: HashMap<u32, ArpEntry>,
// entry: [ArpEntry; ARP_TABLE_SIZE],
}
impl ArpInfo {
fn lookup_ip_mac(&self, ip: u32) -> Option<([u8; 6], u32, bool)> {
if ip == BROADCAST_IPADDR {
return Some((BROADCAST_MAC, ip, false));
}
let edge = get_edge();
let netbit = edge.device_config.get_net_bit();
let host_netmask = net_bit_len_to_mask(netbit);
let host_netmask_reverse = !host_netmask;
if (ip & host_netmask_reverse) == host_netmask_reverse {
return Some((BROADCAST_MAC, ip, false));
}
let first_ip = (ip >> 24) as u8 & 0xff;
if first_ip >= 224 && first_ip <= 239 {
let mut multi = MULTICAST_MAC;
multi[3] = (ip >> 16) as u8 & 0x7f;
multi[4] = (ip >> 8) as u8 & 0xff;
multi[5] = (ip) as u8 & 0xff;
return Some((multi, ip, false));
}
let mut target_ip = 0;
let host_ip = edge.device_config.get_ip();
if (ip & host_netmask) == (host_ip & host_netmask) {
target_ip = ip;
}
if target_ip == 0 {
// let route_table = get_route_table();
if let Some((_prefix, gateway_ip)) = edge.route_table.route_table.lookup(ip) {
// if let Some(gateway_ip) = route_table.get_gateway_ip(ip) {
target_ip = gateway_ip.into();
}
}
if target_ip == 0 {
error!("target should not route to me: ip = {}", ip_to_string(&ip));
return None;
}
if let Some(entry) = self.entry.get(&target_ip) {
return Some((entry.hw_addr, target_ip, false));
}
/*
for i in 0..ARP_TABLE_SIZE {
let item = &self.entry[i];
if item.ip_addr == target_ip {
return (item.hw_addr, target_ip, false);
}
}
*/
return Some((BROADCAST_MAC, target_ip, true));
}
fn set_arp(&mut self, mac: [u8; 6], ip: u32) {
// println!("setting ip: {:?} is at {:?}", ip.to_be_bytes(), mac);
let nowage = ARPTIME.load(Ordering::Relaxed);
self.entry.insert(
ip,
ArpEntry {
ip_addr: ip,
hw_addr: mac,
arptime: nowage,
},
);
/*
for i in 0..ARP_TABLE_SIZE {
let item = &mut self.entry[i];
if item.ip_addr != 0 {
if item.ip_addr == ip {
item.hw_addr = mac;
let nowage = ARPTIME.load(Ordering::Relaxed);
item.arptime = nowage;
return;
}
}
}
*/
/*
println!("set_arp 1");
let mut itemindex = ARP_TABLE_SIZE;
for i in 0..ARP_TABLE_SIZE {
let temp = &self.entry[i];
println!("set arp 2");
if temp.ip_addr == 0 {
itemindex = i;
println!("set arp 3: itemindex = {}", itemindex);
break;
}
}
let arptime = ARPTIME.load(Ordering::Relaxed);
if itemindex == ARP_TABLE_SIZE {
println!("set_arp 4");
let mut tmpage = 0;
let mut idx = 0;
for i in 0..ARP_TABLE_SIZE {
let temp = &self.entry[i];
if (arptime - temp.arptime) > tmpage {
tmpage = arptime - temp.arptime;
idx = i;
}
}
itemindex = idx;
}
println!("set_arp 5");
let temp = &mut self.entry[itemindex];
temp.arptime = arptime;
temp.ip_addr = ip;
temp.hw_addr = mac;
println!("set arp 6: idx={} => {:?}", itemindex, temp);
*/
}
fn timer(&mut self) {
let timer = ARPTIME.fetch_add(1, Ordering::Relaxed);
let mut todelete = vec![];
for (ip, entry) in &self.entry {
if (timer - entry.arptime) >= ARP_MAX_AGE {
todelete.push(*ip);
}
}
for ip in todelete {
self.entry.remove(&ip);
}
/*
for i in 0..ARP_TABLE_SIZE {
let item = &mut self.entry[i];
if item.ip_addr != 0 && (timer - item.arptime) >= ARP_MAX_AGE {
item.ip_addr = 0;
}
}
*/
}
}
*/
/*
pub enum ArpRequestInfo {
Lookup { ip: u32 },
Set { ip: u32, mac: Mac },
}
pub struct ArpRequest {
req: ArpRequestInfo,
tx: oneshot::Sender<ArpResponse>,
}
#[derive(Debug)]
#[allow(unused)]
pub enum ArpResponse {
LookupResp {
mac: Mac,
ip: u32,
do_arp_request: bool,
},
SetResp {
ok: bool,
},
ArpRespError {
msg: String,
},
}
#[derive(Debug)]
pub struct ArpActor {
pub tx: Sender<ArpRequest>,
}
impl ArpActor {
pub fn new() -> Self {
let (tx, rx) = channel(20);
tokio::spawn(loop_arp_info(rx));
Self { tx }
}
}
async fn loop_arp_info(mut rx: Receiver<ArpRequest>) {
let mut arp = ArpInfo {
// entry: array::from_fn(|_i| ArpEntry::new()),
entry: HashMap::new(),
};
loop {
tokio::select! {
data = rx.recv() => {
if let Some(d) = data {
match d.req {
ArpRequestInfo::Lookup{ip} => {
let Some(mac) = arp.lookup_ip_mac(ip) else {
continue;
};
if let Err(e) = d.tx.send(ArpResponse::LookupResp {
mac: mac.0, ip: mac.1, do_arp_request: mac.2 }
) {
error!("failed to send back arp lookup feedback: {:?}", e);
};
}
ArpRequestInfo::Set{ip, mac} => {
arp.set_arp(mac, ip);
if let Err(e) = d.tx.send(ArpResponse::SetResp { ok: true }) {
error!("failed to send back arp set feedback: {:?}", e);
}
}
}
}
}
_ = tokio::time::sleep(Duration::from_secs(10)) => {
arp.timer();
}
}
}
}
pub async fn send_arp_request(data: ArpRequestInfo) -> ArpResponse {
let (tx, rx) = oneshot::channel();
let arp = get_arp();
if let Err(e) = arp.tx.send(ArpRequest { tx, req: data }).await {
error!("failed to send arp request: {}", e);
return ArpResponse::ArpRespError {
msg: "failed to send arp request".to_owned(),
};
}
match rx.await {
Ok(res) => res,
Err(e) => ArpResponse::ArpRespError { msg: e.to_string() },
}
}
*/
pub fn generate_arp_request(srcmac: [u8; 6], dstip: u32, srcip: u32) -> Vec<u8> {
let mut arphdr = ArpHdr::new();
arphdr.ethhdr.dest = [0xff; 6];
arphdr.dhwaddr = [0; 6];
arphdr.ethhdr.src = srcmac;
arphdr.shwaddr = srcmac;
arphdr.dipaddr = [(dstip >> 16) as u16, (dstip & 0xffff) as u16];
arphdr.sipaddr = [(srcip >> 16) as u16, (srcip & 0xffff) as u16];
/*
println!(
"arphdr.sipaddr: {:?}, {:?}",
arphdr.sipaddr[0].to_be_bytes(),
arphdr.sipaddr[1].to_be_bytes()
);
println!(
"arphdr.dipaddr: {:?}, {:?}",
arphdr.dipaddr[0].to_be_bytes(),
arphdr.dipaddr[1].to_be_bytes()
);
*/
arphdr.marshal_to_bytes()
}
#[derive(Debug)]
pub struct ArpWaitInfo {
timestamp: u64,
// origin data is from the tun or tap device
origin_data: BytesMut,
}
pub const MAX_WAIT_PACKETS: usize = 100;
#[derive(Debug)]
pub struct ArpWaitList {
content: DashMap<u32, Vec<ArpWaitInfo>>,
}
impl ArpWaitList {
fn new() -> Self {
Self {
content: DashMap::new(),
}
}
fn add_to_wait_list(&self, ip: u32, origin_data: BytesMut) {
let mut entry = self.content.entry(ip).or_insert(vec![]);
if entry.len() < MAX_WAIT_PACKETS {
entry.push(ArpWaitInfo {
timestamp: get_current_timestamp(),
origin_data,
})
}
}
async fn arp_arrived(&self, ip: u32, mac: Mac) {
debug!(
"arp for {} arrived: {}",
ip_to_string(&ip),
mac_to_string(&mac)
);
let Some(items) = self.content.remove(&ip) else {
return;
};
let edge = get_edge();
// just remove the items
if !edge.is_authorized() {
return;
}
// let encrypt_key = edge.get_encrypt_key();
let network_id = edge.network_id.load(Ordering::Relaxed);
let src_mac = edge.device_config.get_mac();
let now = get_current_timestamp();
for item in items.1 {
if (now - item.timestamp) > 5 {
continue;
}
let packet = form_ethernet_packet(src_mac, mac, item.origin_data);
let pkt_size = packet.len();
let Ok(encrypted) = edge.encryptor.load().encrypt(&packet) else {
// let Ok(encrypted) = edge.encryptor.read().unwrap().encrypt(&packet) else {
// let Ok(encrypted) = aes_encrypt(&encrypt_key, &packet) else {
error!("failed to encrypt packet request");
return;
};
let data_bytes = Bytes::from(encrypted);
let data = SdlData {
is_p2p: true,
network_id,
ttl: SDLAN_DEFAULT_TTL as u32,
src_mac: Vec::from(src_mac),
dst_mac: Vec::from(mac),
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, mac, &msg, pkt_size as u64).await;
}
}
}