route add

This commit is contained in:
asxalex 2026-04-20 16:30:54 +08:00
parent c3355db8ee
commit 7e7a9ca2e6
8 changed files with 568 additions and 369 deletions

View File

@ -16,7 +16,7 @@ once_cell = "1.19.0"
prost = "0.12.6"
prost-build = "0.12.6"
rand = "0.8.5"
reqwest = { version = "0.12.24", default_features = false, features = ["json", "rustls-tls"] }
reqwest = { version = "0.12.24", default-features = false, features = ["json", "rustls-tls"] }
rsa = "0.9.6"
# sdlan-sn-rs = { git = "ssh://git@git2.asxalex.pw/sdlan-v2/sdlan-rs.git" }
sdlan-sn-rs = {git = "https://gitea.s5s8.com/punchnet/sdlan-rs.git"}

View File

@ -5,8 +5,8 @@ use std::fs;
use std::fs::OpenOptions;
use std::process;
use std::env;
use clap::Parser;
use std::env;
#[cfg(not(target_os = "windows"))]
use daemonize::Daemonize;
@ -14,11 +14,7 @@ use daemonize::Daemonize;
use futures_util::io;
#[cfg(not(target_os = "windows"))]
use libc::{SIGTERM, kill};
use punchnet::CachedLoginInfo;
use punchnet::CommandLineInput2;
use punchnet::Commands;
use punchnet::ExitNodeCmd;
use libc::{kill, SIGTERM};
use punchnet::get_access_token;
use punchnet::get_base_dir;
use punchnet::get_edge;
@ -28,31 +24,34 @@ use punchnet::restore_dns;
use punchnet::run_sdlan;
use punchnet::set_access_token;
use punchnet::set_base_dir;
use punchnet::CachedLoginInfo;
use punchnet::CommandLine;
use punchnet::CommandLineInput2;
use punchnet::Commands;
use punchnet::ExitNodeCmd;
use sdlan_sn_rs::log;
use sdlan_sn_rs::utils::create_or_load_uuid;
use sdlan_sn_rs::utils::Mac;
use sdlan_sn_rs::utils::Result;
use sdlan_sn_rs::utils::create_or_load_uuid;
use tokio::runtime::Runtime;
use tracing::debug;
use tracing::error;
use std::net::ToSocketAddrs;
use crate::api::connect;
use crate::api::login_with_token;
use crate::api::login_with_user_pass;
use crate::api::ConnectData;
use crate::api::ConnectResponse;
use crate::api::LoginData;
use crate::api::LoginResponse;
use crate::api::TEST_PREFIX;
use crate::api::connect;
use crate::api::login_with_token;
use crate::api::login_with_user_pass;
use crate::local_udp_info::handle_query_for_info_info;
use crate::local_udp_info::query_for_exit_node_list;
use crate::local_udp_info::query_for_info;
const APP_USER_ENV_NAME: &str = "PUNCH_USER";
const APP_PASS_ENV_NAME: &str = "PUNCH_PASS";
const APP_TOKEN_ENV_NAME: &str = "PUNCH_TOKEN";
@ -162,12 +161,12 @@ async fn daemonize_me(
client_id,
mac,
CommandLine {
sn: server.clone()+":1365",
sn: server.clone() + ":1365",
quic: server.clone() + ":443",
quic_domain: hostname,
nat_server1: server.clone() +":1365",
nat_server1: server.clone() + ":1365",
// nat_server2: "47.98.178.3:1265".to_owned(),
nat_server2: server.clone() +":1366",
nat_server2: server.clone() + ":1366",
allow_routing: allow_routing,
_drop_multicast: true,
register_ttl: 1,
@ -224,17 +223,20 @@ async fn daemonize_me(
eprintln!("got ip from network is invlid: {}", connect_info.ip);
process::exit(-5);
};
if let Err(e) = edge.start_without_feedback(
remembered.access_token.clone(),
// String::new(),
remembered.network_id,
&remembered.network_domain,
ip_net,
connect_info.mask_len,
connect_info.identity_id,
// 0,
None,
).await {
if let Err(e) = edge
.start_without_feedback(
remembered.access_token.clone(),
// String::new(),
remembered.network_id,
&remembered.network_domain,
ip_net,
connect_info.mask_len,
connect_info.identity_id,
// 0,
None,
)
.await
{
error!("failed to start: {:?}", e);
}
@ -277,7 +279,6 @@ async fn daemonize_me(
// started = !started;
// */
// }
}
#[cfg(target_os = "windows")]
@ -285,13 +286,11 @@ const SYSTEM: &'static str = "windows";
#[cfg(target_os = "windows")]
const DEFAULT_BASE_DIR: &'static str = ".";
#[cfg(not(target_os = "windows"))]
const SYSTEM: &'static str = "linux";
#[cfg(target_os = "linux")]
const DEFAULT_BASE_DIR: &'static str = "/usr/local/punchnet";
fn main() {
set_base_dir(DEFAULT_BASE_DIR);
// let _guard = log::init_log(&format!("{}/.output", get_base_dir()));
@ -313,9 +312,18 @@ fn main() {
match &cmd.cmd {
Commands::Login(user) => {
let rt = Runtime::new().unwrap();
rt.block_on( async move {
rt.block_on(async move {
let _ = parse_login_result(
login_with_user_pass(TEST_PREFIX, &client_id, &user.username, &user.password, mac, system, version).await
login_with_user_pass(
TEST_PREFIX,
&client_id,
&user.username,
&user.password,
mac,
system,
version,
)
.await,
);
});
process::exit(0);
@ -325,7 +333,8 @@ fn main() {
let rt = Runtime::new().unwrap();
rt.block_on(async move {
let _ = parse_login_result(
login_with_token(TEST_PREFIX, &client_id, &tk.token, mac, system, version).await
login_with_token(TEST_PREFIX, &client_id, &tk.token, mac, system, version)
.await,
);
});
process::exit(0);
@ -338,14 +347,9 @@ fn main() {
ExitNodeCmd::List => {
query_for_exit_node_list().await;
}
ExitNodeCmd::Start(info) => {
}
ExitNodeCmd::Stop => {
}
ExitNodeCmd::Start(info) => {}
ExitNodeCmd::Stop => {}
}
});
process::exit(0);
}
@ -399,12 +403,14 @@ fn main() {
.create(true)
.truncate(true)
.write(true)
.open("/tmp/punchnet.out").unwrap();
.open("/tmp/punchnet.out")
.unwrap();
let err = OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open("/tmp/punchnet.err").unwrap();
.open("/tmp/punchnet.err")
.unwrap();
let daemonize = Daemonize::new()
.pid_file("/tmp/punchnet.pid")
@ -412,8 +418,7 @@ fn main() {
.working_directory(get_base_dir())
.stdout(out)
.stderr(err)
.privileged_action(|| {
});
.privileged_action(|| {});
match daemonize.start() {
Ok(_) => {
@ -431,49 +436,71 @@ fn main() {
run_it(cmd, client_id, allow_routing, mac, system, version);
}
fn run_it(cmd: CommandLineInput2, client_id: String, allow_routing: bool, mac: Mac, system: &str, version: &str) {
fn run_it(
cmd: CommandLineInput2,
client_id: String,
allow_routing: bool,
mac: Mac,
system: &str,
version: &str,
) {
let rt = Runtime::new().unwrap();
match &cmd.cmd {
Commands::Start(rtinfo) => {
rt.block_on(async move {
let remembered_token = get_access_token();
if remembered_token.is_none() {
eprintln!("not logged in, should login with user/pass or token first");
process::exit(-2);
}
let remembered = remembered_token.unwrap();
let connect_info = parse_connect_result(
connect(TEST_PREFIX, &client_id, &remembered.access_token).await
Commands::Start(rtinfo) => rt.block_on(async move {
let remembered_token = get_access_token();
if remembered_token.is_none() {
eprintln!("not logged in, should login with user/pass or token first");
process::exit(-2);
}
let remembered = remembered_token.unwrap();
let connect_info = parse_connect_result(
connect(TEST_PREFIX, &client_id, &remembered.access_token).await,
);
daemonize_me(
rtinfo.allow_routing || allow_routing,
connect_info,
remembered,
client_id,
rtinfo.route_file.clone(),
rtinfo.route.clone(),
mac,
)
.await;
}),
Commands::AutoRun(tk) => rt.block_on(async move {
let mut remembered_token = get_access_token();
if remembered_token.is_none() {
let data = parse_login_result(
login_with_token(TEST_PREFIX, &client_id, &tk.token, mac, system, version)
.await,
);
daemonize_me(rtinfo.allow_routing || allow_routing, connect_info, remembered, client_id, rtinfo.route_file.clone(), rtinfo.route.clone(), mac).await;
})
}
Commands::AutoRun(tk) => {
rt.block_on(async move {
let mut remembered_token = get_access_token();
if remembered_token.is_none() {
let data = parse_login_result(
login_with_token(TEST_PREFIX, &client_id, &tk.token, mac, system, version).await
);
remembered_token = Some(CachedLoginInfo{
access_token: data.access_token,
username: data.username,
user_type: data.user_type,
audit: data.audit,
network_id: data.network_id,
network_name: data.network_name,
network_domain: data.network_domain,
});
}
remembered_token = Some(CachedLoginInfo {
access_token: data.access_token,
username: data.username,
user_type: data.user_type,
audit: data.audit,
network_id: data.network_id,
network_name: data.network_name,
network_domain: data.network_domain,
});
}
let remembered = remembered_token.unwrap();
let remembered = remembered_token.unwrap();
let connect_info = parse_connect_result(
connect(TEST_PREFIX, &client_id, &remembered.access_token).await
);
daemonize_me(tk.allow_routing || allow_routing, connect_info, remembered, client_id, tk.route_file.clone(), tk.route.clone(), mac).await;
})
}
let connect_info = parse_connect_result(
connect(TEST_PREFIX, &client_id, &remembered.access_token).await,
);
daemonize_me(
tk.allow_routing || allow_routing,
connect_info,
remembered,
client_id,
tk.route_file.clone(),
tk.route.clone(),
mac,
)
.await;
}),
other => {
eprintln!("should not comes here");

View File

@ -2,7 +2,10 @@
use std::{
collections::HashMap,
sync::{Arc, atomic::{AtomicU8, Ordering}},
sync::{
atomic::{AtomicU8, Ordering},
Arc,
},
time::{Duration, Instant},
};
@ -11,15 +14,25 @@ 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 sdlan_sn_rs::{
config::SDLAN_DEFAULT_TTL,
utils::{
get_current_timestamp, ip_to_string, mac_to_string, net_bit_len_to_mask, Mac,
BROADCAST_MAC, MULTICAST_MAC,
},
};
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 crate::{
network::{form_ethernet_packet, send_packet_to_net},
pb::{encode_to_udp_message, SdlData},
tcp::PacketType,
};
use super::{get_edge};
use super::get_edge;
/*
static GLOBAL_ARP: OnceCell<ArpActor> = OnceCell::new();
@ -164,8 +177,6 @@ impl ArpEntry {
}
*/
pub struct ArpTable {
entries: Arc<DashMap<u32, ArpEntry>>,
ttl: Duration,
@ -181,7 +192,7 @@ impl ArpTable {
pending_packet_buffer: ArpWaitList::new(),
};
let mut bytes = BytesMut::with_capacity(1024+20);
let mut bytes = BytesMut::with_capacity(1024 + 20);
let ttl = res.ttl;
tokio::spawn(async move {
@ -199,6 +210,7 @@ impl ArpTable {
self.pending_packet_buffer.arp_arrived(ip, mac).await;
}
/// origin_data is layer3(ip) packet
pub fn add_to_arp_wait_list(&self, ip: u32, origin_data: BytesMut) {
self.pending_packet_buffer.add_to_wait_list(ip, origin_data);
}
@ -484,7 +496,6 @@ pub fn generate_arp_request(srcmac: [u8; 6], dstip: u32, srcip: u32) -> Vec<u8>
arphdr.marshal_to_bytes()
}
#[derive(Debug)]
pub struct ArpWaitInfo {
timestamp: u64,
@ -492,7 +503,6 @@ pub struct ArpWaitInfo {
origin_data: BytesMut,
}
pub const MAX_WAIT_PACKETS: usize = 100;
#[derive(Debug)]
@ -507,7 +517,6 @@ impl ArpWaitList {
}
}
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 {
@ -547,8 +556,8 @@ impl ArpWaitList {
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 {
// 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;
};

View File

@ -1,15 +1,32 @@
use std::{collections::HashMap, fs, io::{BufRead, BufReader}, net::Ipv4Addr, sync::{Arc, atomic::{AtomicBool, Ordering}}, time::Duration};
use std::{
collections::HashMap,
fs,
io::{BufRead, BufReader},
net::Ipv4Addr,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
time::Duration,
};
use ahash::RandomState;
use arc_swap::ArcSwap;
use dashmap::{DashMap};
use dashmap::DashMap;
use ipnet::Ipv4Net;
use sdlan_sn_rs::utils::{Result, SDLanError};
use tokio::{io::ReadBuf, sync::oneshot::{Receiver, Sender, channel}};
use tracing::{debug, error};
use tokio::{
io::ReadBuf,
sync::oneshot::{channel, Receiver, Sender},
};
use tracing::{debug, error, warn};
use crate::{RouteTableTrie, network::tun::{add_route, del_route}, pb::{SdlArpResponse, SdlStunReply}};
use crate::{
network::tun::{add_route, del_route},
pb::{SdlArpResponse, SdlStunReply},
RouteTableTrie,
};
#[derive(Debug)]
pub struct RouteInfo {
@ -51,6 +68,7 @@ impl RouteTable2 {
if net.addr().to_bits() == 0 {
// default gateway
self.default_gw.store(Arc::new(Some(gw.clone())));
continue;
}
if route.value().load(Ordering::Relaxed) {
if let Err(e) = del_route(net, gw) {
@ -62,8 +80,11 @@ impl RouteTable2 {
self.route_table.clear();
for route in routes {
self.cache_table.insert((route.net, route.gw), AtomicBool::new(false));
self.route_table.insert(route.net.addr().into(), route.net.prefix_len(), route.gw);
self.cache_table
.insert((route.net, route.gw), AtomicBool::new(false));
warn!("inserting route {} gw {}", route.net, route.gw);
self.route_table
.insert(route.net.addr().into(), route.net.prefix_len(), route.gw);
}
Ok(())
}
@ -71,20 +92,17 @@ impl RouteTable2 {
/// parse the route_file or route_str and add to the route table.
pub fn parse_and_add_route(&self, route_file: &str, route_str: &str) -> Result<()> {
let routes = match true {
_ if route_str.len() != 0 => {
parse_route(route_str)
}
_ if route_file.len() != 0 => {
load_route_file(route_file)
}
_ => {
Ok(HashMap::new())
}
_ if route_str.len() != 0 => parse_route(route_str),
_ if route_file.len() != 0 => load_route_file(route_file),
_ => Ok(HashMap::new()),
}?;
for route in routes.keys() {
if self.cache_table.get(route).is_some() {
error!("route {} {} has been added", route.0.to_string(), route.1);
return Err(SDLanError::IOError(format!("route {} already added", route.0.to_string())));
return Err(SDLanError::IOError(format!(
"route {} already added",
route.0.to_string()
)));
}
}
@ -100,21 +118,38 @@ impl RouteTable2 {
self.route_table.clear();
for route in routes.keys() {
debug!("got route: {} gw {}", route.0, route.1);
self.cache_table.insert(*route, AtomicBool::new(false));
self.route_table.insert(route.0.addr().into(), route.0.prefix_len(), route.1);
warn!(
"inserting to route table: {} mask {} gw {}",
route.0.addr(),
route.0.prefix_len(),
route.1
);
self.route_table.insert(
u32::from_be_bytes(route.0.addr().octets()),
route.0.prefix_len(),
route.1,
);
}
Ok(())
}
pub fn apply_system(&self) {
pub fn apply_system(&self, if_idx: u32) {
debug!("applying system");
for route in &self.cache_table {
let (net, gw) = route.key();
debug!("route is {} gw {}", net, gw);
if !route.value().load(Ordering::Relaxed) {
if let Err(e) = add_route(net, gw) {
debug!("adding route: {} gw {}", net, gw);
if let Err(e) = add_route(net, gw, if_idx) {
error!("failed to add route: {}", e.as_str());
} else {
route.value().store(true, Ordering::Relaxed);
}
}
// should add to system
// should add to system
}
}
}
@ -150,7 +185,7 @@ pub fn parse_a_route(route: &str) -> Result<(Ipv4Net, Ipv4Addr)> {
};
let cidr = route_info[0];
let Ok(net )= cidr.parse::<Ipv4Net>() else {
let Ok(net) = cidr.parse::<Ipv4Net>() else {
error!("failed to parse cidr: {}, skipping", cidr);
return Err(SDLanError::IOError("failed to parse cidr".to_string()));
};

View File

@ -4,7 +4,7 @@ use etherparse::{Ethernet2Header, IpHeaders, NetSlice, SlicedPacket, TransportSl
use ipnet::Ipv4Net;
use sdlan_sn_rs::config::SDLAN_DEFAULT_TTL;
use sdlan_sn_rs::utils::{
BROADCAST_MAC, Result, aes_encrypt, ip_to_string, is_multi_broadcast, net_bit_len_to_mask
aes_encrypt, ip_to_string, is_multi_broadcast, net_bit_len_to_mask, Result, BROADCAST_MAC,
};
use std::io::{Error, ErrorKind};
use std::net::Ipv4Addr;
@ -15,13 +15,14 @@ use std::sync::Arc;
use tracing::{debug, error, info};
use wintun;
use crate::{caculate_crc, get_edge};
use crate::network::{
ARP_REPLY, ARP_REQUEST, ArpHdr, DNS_IP, Node, form_ethernet_packet, generate_arp_request, parse_dns_payload, send_packet_to_net
form_ethernet_packet, generate_arp_request, parse_dns_payload, send_packet_to_net, ArpHdr,
Node, ARP_REPLY, ARP_REQUEST, DNS_IP,
};
use crate::pb::{SdlArpResponse, SdlData, encode_to_udp_message};
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;
@ -34,6 +35,10 @@ pub struct Iface {
}
impl Iface {
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"));
@ -124,15 +129,15 @@ impl Iface {
if let Err(e) = set_dns(&self.name, network_domain, &ip, self.if_idx) {
error!("failed to set dns: {:?}", e);
} else {
error!("set dns ok");
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;
@ -247,7 +252,6 @@ impl TunTapPacketHandler for Iface {
}
}
ARP_REPLY => {
debug!("mac {:?} is at {:?}", arp.shwaddr, from_ip.to_be_bytes());
if dest_ip == self_ip {
/*
@ -316,140 +320,137 @@ impl TunTapPacketHandler for Iface {
}
// async fn handle_packet_from_device(
// &self,
// data: BytesMut,
// // encrypt_key: &[u8],
// &self,
// data: BytesMut,
// // encrypt_key: &[u8],
// ) -> std::io::Result<()> {
// let eee = get_edge();
// let eee = get_edge();
// let src_mac = eee.device_config.get_mac();
// 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.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 {
// // 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);
// 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.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 {
// // 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());
// 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) = eee.encryptor.load().encrypt(&arp_msg) else {
// // 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: Bytes::from(encrypted),
// let Ok(encrypted) = eee.encryptor.load().encrypt(&arp_msg) else {
// // 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: Bytes::from(encrypted),
// session_token: eee.session_token.get(),
// identity_id: eee.identity_id.load(),
// };
// 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(&etherheader.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 {
// let Ok(encrypted) = eee.encryptor.load().encrypt(&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: 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;
// // let dstip = u32::from_be_bytes(ipv4hdr.0.destination);
// }
// _ => {}
// }
// }
// Err(e) => {
// error!("failed to parse ip packet: {}", e.to_string());
// }
// }
// Ok(())
// session_token: eee.session_token.get(),
// identity_id: eee.identity_id.load(),
// };
// 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(());
// }
async fn handle_packet_from_device(
&self,
mut header: BytesMut,
) -> std::io::Result<()> {
// 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(&etherheader.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 {
// let Ok(encrypted) = eee.encryptor.load().encrypt(&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: 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;
// // let dstip = u32::from_be_bytes(ipv4hdr.0.destination);
// }
// _ => {}
// }
// }
// Err(e) => {
// error!("failed to parse ip packet: {}", e.to_string());
// }
// }
// Ok(())
// }
async fn handle_packet_from_device(&self, mut header: BytesMut) -> std::io::Result<()> {
use etherparse::IpHeaders;
let eee = get_edge();
@ -467,10 +468,8 @@ impl TunTapPacketHandler for Iface {
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));
@ -479,7 +478,9 @@ impl TunTapPacketHandler for Iface {
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()) {
if (!eee.config.allow_routing.load(Ordering::Relaxed))
&& (src != eee.device_config.get_ip())
{
info!("dropping routed packet");
return Ok(());
}
@ -498,14 +499,19 @@ impl TunTapPacketHandler for Iface {
// should do the dns request
// println!("request for dns");
parse_dns_payload(eee, udp.payload(), &data, src, udp.source_port()).await;
parse_dns_payload(
eee,
udp.payload(),
&data,
src,
udp.source_port(),
)
.await;
// edge.udp_sock_for_dns.send_to()
return Ok(());
}
}
_other => {
}
_other => {}
}
match eee.arp_table.get(dstip) {
@ -522,7 +528,6 @@ impl TunTapPacketHandler for Iface {
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());
@ -554,38 +559,42 @@ impl TunTapPacketHandler for Iface {
}
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());
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;
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(dstip, real_ip).await;
let _ = eee.send_arp_request(real_ip, dstip).await;
}
}
}
}
}
}
NetSlice::Ipv6(ipv6) => {
}
NetSlice::Ipv6(ipv6) => {}
}
Ok(())
}
/*
async fn handle_packet_from_device(
&self,
@ -717,7 +726,9 @@ fn create_wintun(path: &str, name: &str) -> Iface {
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");
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 {
@ -737,7 +748,7 @@ 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<()>{
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")
@ -769,11 +780,10 @@ pub fn set_dns(name: &str, _network_domain: &str, gw: &str, ifidx: u32) -> std::
Ok(())
}
pub fn restore_dns() {
}
pub fn restore_dns() {}
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")
@ -783,32 +793,54 @@ pub fn del_route(net: &Ipv4Net, gw: &Ipv4Addr) -> Result<()> {
.arg(gw.to_string())
.output()?;
Ok(())
}
pub fn add_route(net: &Ipv4Net, gw: &Ipv4Addr) -> Result<()> {
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 res = Command::new("route")
match Command::new("route")
.arg("add")
.arg(network)
.arg("MASK")
.arg(mask)
.arg(gw.to_string())
.output()?;
Ok(())
}
.arg("if")
.arg(format!("{}", if_idx))
.output()
{
Err(e) => {
error!("failed to add route: {}", e);
Err(e.into())
}
Ok(value) => {
debug!(
"add route ok: {}, out={:?}, err={}",
value.status,
String::from_utf8_lossy(value.stdout.as_slice()),
String::from_utf8_lossy(value.stderr.as_slice()),
);
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));
error!(
"invalid target_mac: {:?}, ip={}",
data.target_mac,
ip_to_string(&data.target_ip)
);
return;
}
let ip = data.target_ip;
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;
}

View File

@ -1,4 +1,3 @@
use std::sync::atomic::Ordering;
use bytes::{Bytes, BytesMut};
@ -6,7 +5,7 @@ use dashmap::DashMap;
use once_cell::sync::OnceCell;
use sdlan_sn_rs::{
config::SDLAN_DEFAULT_TTL,
utils::{Mac, Result, get_current_timestamp, ip_to_string},
utils::{get_current_timestamp, ip_to_string, Mac, Result},
};
use tracing::{debug, warn};
@ -14,8 +13,8 @@ use tracing::{debug, warn};
use tracing::error;
use crate::{
network::{Node, RouteInfo, form_ethernet_packet, send_packet_to_net},
pb::{SdlData, encode_to_udp_message},
network::{form_ethernet_packet, send_packet_to_net, Node, RouteInfo},
pb::{encode_to_udp_message, SdlData},
tcp::PacketType,
utils::mac_to_string,
};
@ -24,18 +23,17 @@ use super::get_edge;
pub const MAX_WAIT_PACKETS: usize = 100;
const DEFAULT_DNS_SERVER: u32 = (223<<24) + (5<<16) + (5<<8) + 5; // ali dns
const DEFAULT_DNS_SERVER: u32 = (223 << 24) + (5 << 16) + (5 << 8) + 5; // ali dns
pub trait TunTapPacketHandler {
async fn handle_packet_from_net(&self, data: &[u8]) -> std::io::Result<()>;
async fn handle_packet_from_device(&self, data: BytesMut) -> std::io::Result<()>;
}
pub fn set_route_from_net(routes: Vec<RouteInfo>) -> Result<()>{
pub fn set_route_from_net(routes: Vec<RouteInfo>) -> Result<()> {
let eee = get_edge();
eee.route_table.clear_and_add_routes(routes)?;
eee.route_table.apply_system();
eee.route_table.apply_system(eee.device.get_if_idx());
Ok(())
}
@ -149,7 +147,6 @@ pub fn get_dns_gateway(edge: &Node, payload: &[u8]) -> Option<String> {
Ok(p) => p,
};
let mut target_dns: &str = "";
if !dns_packet.has_flags(simple_dns::PacketFlag::RESPONSE) && !dns_packet.questions.is_empty() {
let question = &dns_packet.questions[0];
@ -168,27 +165,55 @@ pub fn get_dns_gateway(edge: &Node, payload: &[u8]) -> Option<String> {
return None;
}
pub async fn parse_dns_payload(edge: &Node, layer7: &[u8], layer3: &[u8], source_ip: u32, source_port: u16) {
pub async fn parse_dns_payload(
edge: &Node,
layer7: &[u8],
layer3: &[u8],
source_ip: u32,
source_port: u16,
) {
match simple_dns::Packet::parse(layer7) {
Ok(mut dns) => {
if !dns.has_flags(simple_dns::PacketFlag::RESPONSE) && !dns.questions.is_empty() {
let question = &dns.questions[0];
let qname = question.qname.to_string();
if qname.ends_with(edge.network_domain.load().as_str()) {
warn!("question 15353 for {} from {}:{} with transaction_id = {}",
qname, ip_to_string(&source_ip), source_port, dns.id());
warn!(
"question 15353 for {} from {}:{} with transaction_id = {}",
qname,
ip_to_string(&source_ip),
source_port,
dns.id()
);
// should send to our socket
if let Err(e) = edge.udp_sock_for_dns.send_to(layer3, format!("{}:15353", edge.server_ip)).await {
if let Err(e) = edge
.udp_sock_for_dns
.send_to(layer3, format!("{}:15353", edge.server_ip))
.await
{
error!("failed to send request to 15353: {}", e);
}
} else {
let origin_transaction_id = dns.id();
let transaction_id = edge.dns_matcher.generate_transaction_id(source_ip, source_port, origin_transaction_id);
let transaction_id = edge.dns_matcher.generate_transaction_id(
source_ip,
source_port,
origin_transaction_id,
);
dns.set_id(transaction_id);
warn!("question 223.5.5.5 for {} from {}:{} with transaction_id = {}",
qname, ip_to_string(&source_ip), source_port, dns.id());
warn!(
"question 223.5.5.5 for {} from {}:{} with transaction_id = {}",
qname,
ip_to_string(&source_ip),
source_port,
dns.id()
);
if let Ok(res) = dns.build_bytes_vec() {
if let Err(e) = edge.udp_sock_for_global_dns.send_to(&res, "223.5.5.5:53").await {
if let Err(e) = edge
.udp_sock_for_global_dns
.send_to(&res, "223.5.5.5:53")
.await
{
error!("failed to query for global dns: {}", e);
}
}

View File

@ -1,17 +1,47 @@
use std::{net::IpAddr, sync::{Arc, OnceLock, atomic::{AtomicBool, AtomicU64, Ordering}}, time::Duration};
use std::{
net::IpAddr,
sync::{
atomic::{AtomicBool, AtomicU64, Ordering},
Arc, OnceLock,
},
time::Duration,
};
use futures_util::pin_mut;
use prost::Message;
use quinn::SendStream;
use sdlan_sn_rs::{config::AF_INET, peer::{SdlanSock, V6Info}, utils::{Result, SDLanError, get_current_timestamp, ip_to_string, rsa_decrypt}};
use tokio::{sync::mpsc::{Receiver, Sender, channel}, time::sleep};
use sdlan_sn_rs::{
config::AF_INET,
peer::{SdlanSock, V6Info},
utils::{get_current_timestamp, ip_to_string, rsa_decrypt, Result, SDLanError},
};
use tokio::{
sync::mpsc::{channel, Receiver, Sender},
time::sleep,
};
use tokio_util::sync::CancellationToken;
use tracing::{debug, error, warn, info};
use tracing::{debug, error, info, warn};
#[cfg(target_os = "linux")]
use crate::network::{set_allow_routing, set_disallow_routing};
use crate::{AesEncryptor, Chacha20Encryptor, ConnectionInfo, ConnectionState, MyEncryptor, RuleFromServer, config::{NULL_MAC, TCP_PING_TIME}, get_edge, load_configuration, network::{ARP_REPLY, ArpHdr, EthHdr, Node, RegisterSuperFeedback, StartStopInfo, arp_reply_arrived, check_peer_registration_needed, handle_packet_peer_info}, pb::{SdlArpResponse, SdlCommand, SdlCommandAck, SdlEvent, SdlPolicyResponse, SdlRegisterSuper, SdlRegisterSuperAck, SdlRegisterSuperNak, encode_to_tcp_message, sdl_command, sdl_event::{self, Event, SendRegister}}, store_configuration, tcp::{EventType, NakMsgCode, NatType, PacketType, SdlanTcp, read_a_packet, send_stun_request}};
use crate::{
config::{NULL_MAC, TCP_PING_TIME},
get_edge, load_configuration,
network::{
arp_reply_arrived, check_peer_registration_needed, handle_packet_peer_info, ArpHdr, EthHdr,
Node, RegisterSuperFeedback, StartStopInfo, ARP_REPLY,
},
pb::{
encode_to_tcp_message, sdl_command,
sdl_event::{self, Event, SendRegister},
SdlArpResponse, SdlCommand, SdlCommandAck, SdlEvent, SdlPolicyResponse, SdlRegisterSuper,
SdlRegisterSuperAck, SdlRegisterSuperNak,
},
store_configuration,
tcp::{read_a_packet, send_stun_request, EventType, NakMsgCode, NatType, PacketType, SdlanTcp},
AesEncryptor, Chacha20Encryptor, ConnectionInfo, ConnectionState, MyEncryptor, RuleFromServer,
};
static GLOBAL_QUIC_HANDLE: OnceLock<ReadWriterHandle> = OnceLock::new();
@ -73,7 +103,7 @@ impl ReadWriterHandle {
to_tcp,
// on_connected,
// on_disconnected,
start_stop_chan
start_stop_chan,
)
.await
});
@ -106,7 +136,6 @@ pub fn get_quic_write_conn() -> &'static ReadWriterHandle {
}
}
async fn handle_tcp_message(msg: SdlanTcp) {
let edge = get_edge();
@ -138,19 +167,21 @@ async fn handle_tcp_message(msg: SdlanTcp) {
match ack.algorithm.to_ascii_lowercase().as_str() {
"chacha20" => {
edge.encryptor.store(Arc::new(MyEncryptor::ChaChao20(Chacha20Encryptor::new(key, ack.region_id))))
edge.encryptor
.store(Arc::new(MyEncryptor::ChaChao20(Chacha20Encryptor::new(
key,
ack.region_id,
))))
// *edge.encryptor.write().unwrap() = MyEncryptor::ChaChao20(Chacha20Encryptor::new(key, ack.region_id));
}
"aes" => {
edge.encryptor.store(Arc::new(MyEncryptor::Aes(AesEncryptor::new(key))))
edge.encryptor
.store(Arc::new(MyEncryptor::Aes(AesEncryptor::new(key))))
// *edge.encryptor.write().unwrap() = MyEncryptor::Aes(AesEncryptor::new(key));
}
_other => {
}
_other => {}
}
/*
let Some(dev) = ack.dev_addr else {
error!("no dev_addr is specified");
@ -188,7 +219,8 @@ async fn handle_tcp_message(msg: SdlanTcp) {
edge.network_id.store(dev.network_id, Ordering::Relaxed);
*/
// edge.device.reload_config(&edge.device_config, &dev.network_domain);
edge.device.reload_config(edge, &edge.device_config, &edge.network_domain.load());
edge.device
.reload_config(edge, &edge.device_config, &edge.network_domain.load());
edge.set_authorized(true);
@ -205,7 +237,6 @@ async fn handle_tcp_message(msg: SdlanTcp) {
return;
};
arp_reply_arrived(edge, res).await;
return;
}
@ -222,13 +253,10 @@ async fn handle_tcp_message(msg: SdlanTcp) {
break;
}
let proto = policy.rules[start];
let port = u16::from_be_bytes([policy.rules[start+1], policy.rules[start+2]]);
let port = u16::from_be_bytes([policy.rules[start + 1], policy.rules[start + 2]]);
start += 3;
infos.push(RuleFromServer{
proto,
port,
});
infos.push(RuleFromServer { proto, port });
}
edge.rule_cache.set_identity_cache(identity, infos);
@ -319,7 +347,7 @@ async fn handle_tcp_message(msg: SdlanTcp) {
error!("malformed COMMAND received");
return;
}
handle_tcp_command(edge, &msg.current_packet[..]).await;
handle_tcp_command(edge, &msg.current_packet[..]).await;
}
PacketType::Event => {
if msg.current_packet.len() < 1 {
@ -342,7 +370,6 @@ async fn handle_tcp_message(msg: SdlanTcp) {
}
}
async fn handle_tcp_command(edge: &Node, cmdprotobuf: &[u8]) {
let Ok(cmd) = SdlCommand::decode(cmdprotobuf) else {
error!("failed to decode SdlCommand");
@ -362,7 +389,10 @@ async fn handle_tcp_command(edge: &Node, cmdprotobuf: &[u8]) {
// std::process::exit(0);
if node.action == 0 {
// stop
let origin = edge.config.allow_routing.fetch_and(false, Ordering::Relaxed);
let origin = edge
.config
.allow_routing
.fetch_and(false, Ordering::Relaxed);
let mut config = load_configuration();
config.allow_routing = Some(false);
let _ = store_configuration(&config);
@ -382,7 +412,7 @@ async fn handle_tcp_command(edge: &Node, cmdprotobuf: &[u8]) {
}
}
let ack = SdlCommandAck{
let ack = SdlCommandAck {
pkt_id,
code: 0,
message: "ok".to_owned(),
@ -396,7 +426,6 @@ async fn handle_tcp_command(edge: &Node, cmdprotobuf: &[u8]) {
}
}
}
}
async fn handle_tcp_event(edge: &'static Node, eventprotobuf: &[u8]) {
@ -455,10 +484,8 @@ async fn handle_tcp_event(edge: &'static Node, eventprotobuf: &[u8]) {
debug!("unhandled event {:?}", other);
}
}
}
pub fn init_quic_conn(
cancel: CancellationToken,
addr: &str,
@ -472,8 +499,8 @@ pub fn init_quic_conn(
connecting_chan: Option<Sender<ConnectionInfo>>,
ipv6_network_restarter: Option<Sender<bool>>,
)
// T2: Fn(SdlanTcp) -> F + Send + 'static,
// F: Future<Output = ()> + Send,
// T2: Fn(SdlanTcp) -> F + Send + 'static,
// F: Future<Output = ()> + Send,
{
let tcp_handle = ReadWriterHandle::new(
cancel,
@ -577,7 +604,10 @@ impl ReadWriteActor {
debug!("try connecting to {}", self.domain);
let conn = match edge.quic_endpoint.connect(self.remote.parse().unwrap(), &self.domain) {
let conn = match edge
.quic_endpoint
.connect(self.remote.parse().unwrap(), &self.domain)
{
Ok(conn) => conn,
Err(e) => {
error!("failed to connect: {}", e);
@ -589,7 +619,6 @@ impl ReadWriteActor {
continue;
}
return;
}
};
@ -764,11 +793,8 @@ async fn on_connected_callback(local_ip: Option<IpAddr>, stream: &mut SendStream
// debug!("send register super: {:?}", register_super);
// let packet_id = edge.get_next_packet_id();
let data = encode_to_tcp_message(
Some(register_super),
PacketType::RegisterSuper as u8,
)
.unwrap();
let data =
encode_to_tcp_message(Some(register_super), PacketType::RegisterSuper as u8).unwrap();
if let Err(e) = stream.write(&data).await {
error!("failed to write to tcp: {}", e.to_string());
}

View File

@ -17,7 +17,7 @@ struct IpTrie {
impl IpTrie {
fn new() -> Self {
Self {
root: TrieNode::default()
root: TrieNode::default(),
}
}
@ -28,17 +28,16 @@ impl IpTrie {
let mut node = &mut self.root;
for i in 0..prefix_len {
let bit = ((prefix >> (31-i)) & 1) as usize;
let bit = ((prefix >> (31 - i)) & 1) as usize;
node = node.child[bit].get_or_insert_with(|| Box::new(TrieNode::default()));
}
if prefix_len > node.prefix_len {
if prefix_len >= node.prefix_len {
node.prefix_len = prefix_len;
node.nexthop = Some(nexthop);
}
}
fn lookup(&self, ip: u32) -> Option<(u8, Ipv4Addr)>{
fn lookup(&self, ip: u32) -> Option<(u8, Ipv4Addr)> {
let mut node = &self.root;
let mut best = None;
@ -46,7 +45,8 @@ impl IpTrie {
if node.nexthop.is_some() {
best = Some((node.prefix_len, node.nexthop.unwrap()));
}
let bit = ((ip>>(31-i)) & 1) as usize;
let bit = ((ip >> (31 - i)) & 1) as usize;
// println!("to find bit {} => {}", i, bit);
match &node.child[bit] {
Some(child) => {
node = child;
@ -63,6 +63,51 @@ impl IpTrie {
}
}
#[cfg(test)]
mod test {
use std::net::Ipv4Addr;
use crate::{network::RouteTable2, TrieNode};
#[test]
fn test_trie() {
let trie = RouteTable2::new();
let mut ips: Vec<(Ipv4Addr, Ipv4Addr)> = vec![];
for i in 1..254u32 {
ips.push((
format!("192.168.{}.0", i).parse::<Ipv4Addr>().unwrap(),
format!("192.168.{}.1", i).parse::<Ipv4Addr>().unwrap(),
));
}
for ip in &ips {
trie.route_table
.insert(u32::from_be_bytes(ip.0.octets()), 24, ip.1);
}
for ip in &ips {
let origin = ip.0;
let mut query = origin.octets();
query[3] = 123;
let query = Ipv4Addr::from_octets(query);
println!("query for {}", query);
let result = ip.1;
let Some((prefix, target)) =
trie.route_table.lookup(u32::from_be_bytes(query.octets()))
else {
panic!("failed to lookup: {} for {}", query, result);
};
if prefix != 24 {
panic!("prefix is not 24: {}", prefix);
}
if target != result {
panic!("gateway is not match, {} expected {}", target, result);
}
}
}
}
pub struct RouteTableTrie {
trie: ArcSwap<IpTrie>,
}
@ -70,11 +115,11 @@ pub struct RouteTableTrie {
impl RouteTableTrie {
pub fn new() -> Self {
Self {
trie: ArcSwap::new(Arc::new(IpTrie::default()))
trie: ArcSwap::new(Arc::new(IpTrie::default())),
}
}
pub fn clear(&self) {
pub fn clear(&self) {
self.trie.store(Arc::new(IpTrie::default()));
}