570 lines
16 KiB
Rust
Executable File
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;
|
|
}
|
|
}
|
|
} |