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

View File

@ -2,7 +2,10 @@
use std::{ use std::{
collections::HashMap, collections::HashMap,
sync::{Arc, atomic::{AtomicU8, Ordering}}, sync::{
atomic::{AtomicU8, Ordering},
Arc,
},
time::{Duration, Instant}, time::{Duration, Instant},
}; };
@ -11,15 +14,25 @@ use dashmap::DashMap;
use tracing::{debug, error}; use tracing::{debug, error};
use once_cell::sync::OnceCell; 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::{ use tokio::sync::{
mpsc::{channel, Receiver, Sender}, mpsc::{channel, Receiver, Sender},
oneshot, 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(); static GLOBAL_ARP: OnceCell<ArpActor> = OnceCell::new();
@ -164,8 +177,6 @@ impl ArpEntry {
} }
*/ */
pub struct ArpTable { pub struct ArpTable {
entries: Arc<DashMap<u32, ArpEntry>>, entries: Arc<DashMap<u32, ArpEntry>>,
ttl: Duration, ttl: Duration,
@ -181,7 +192,7 @@ impl ArpTable {
pending_packet_buffer: ArpWaitList::new(), 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; let ttl = res.ttl;
tokio::spawn(async move { tokio::spawn(async move {
@ -199,6 +210,7 @@ impl ArpTable {
self.pending_packet_buffer.arp_arrived(ip, mac).await; 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) { pub fn add_to_arp_wait_list(&self, ip: u32, origin_data: BytesMut) {
self.pending_packet_buffer.add_to_wait_list(ip, origin_data); 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() arphdr.marshal_to_bytes()
} }
#[derive(Debug)] #[derive(Debug)]
pub struct ArpWaitInfo { pub struct ArpWaitInfo {
timestamp: u64, timestamp: u64,
@ -492,7 +503,6 @@ pub struct ArpWaitInfo {
origin_data: BytesMut, origin_data: BytesMut,
} }
pub const MAX_WAIT_PACKETS: usize = 100; pub const MAX_WAIT_PACKETS: usize = 100;
#[derive(Debug)] #[derive(Debug)]
@ -507,7 +517,6 @@ impl ArpWaitList {
} }
} }
fn add_to_wait_list(&self, ip: u32, origin_data: BytesMut) { fn add_to_wait_list(&self, ip: u32, origin_data: BytesMut) {
let mut entry = self.content.entry(ip).or_insert(vec![]); let mut entry = self.content.entry(ip).or_insert(vec![]);
if entry.len() < MAX_WAIT_PACKETS { if entry.len() < MAX_WAIT_PACKETS {

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 ahash::RandomState;
use arc_swap::ArcSwap; use arc_swap::ArcSwap;
use dashmap::{DashMap}; use dashmap::DashMap;
use ipnet::Ipv4Net; use ipnet::Ipv4Net;
use sdlan_sn_rs::utils::{Result, SDLanError}; use sdlan_sn_rs::utils::{Result, SDLanError};
use tokio::{io::ReadBuf, sync::oneshot::{Receiver, Sender, channel}}; use tokio::{
use tracing::{debug, error}; 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)] #[derive(Debug)]
pub struct RouteInfo { pub struct RouteInfo {
@ -51,6 +68,7 @@ impl RouteTable2 {
if net.addr().to_bits() == 0 { if net.addr().to_bits() == 0 {
// default gateway // default gateway
self.default_gw.store(Arc::new(Some(gw.clone()))); self.default_gw.store(Arc::new(Some(gw.clone())));
continue;
} }
if route.value().load(Ordering::Relaxed) { if route.value().load(Ordering::Relaxed) {
if let Err(e) = del_route(net, gw) { if let Err(e) = del_route(net, gw) {
@ -62,8 +80,11 @@ impl RouteTable2 {
self.route_table.clear(); self.route_table.clear();
for route in routes { for route in routes {
self.cache_table.insert((route.net, route.gw), AtomicBool::new(false)); self.cache_table
self.route_table.insert(route.net.addr().into(), route.net.prefix_len(), route.gw); .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(()) Ok(())
} }
@ -71,20 +92,17 @@ impl RouteTable2 {
/// parse the route_file or route_str and add to the route table. /// 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<()> { pub fn parse_and_add_route(&self, route_file: &str, route_str: &str) -> Result<()> {
let routes = match true { let routes = match true {
_ if route_str.len() != 0 => { _ if route_str.len() != 0 => parse_route(route_str),
parse_route(route_str) _ if route_file.len() != 0 => load_route_file(route_file),
} _ => Ok(HashMap::new()),
_ if route_file.len() != 0 => {
load_route_file(route_file)
}
_ => {
Ok(HashMap::new())
}
}?; }?;
for route in routes.keys() { for route in routes.keys() {
if self.cache_table.get(route).is_some() { if self.cache_table.get(route).is_some() {
error!("route {} {} has been added", route.0.to_string(), route.1); 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,18 +118,35 @@ impl RouteTable2 {
self.route_table.clear(); self.route_table.clear();
for route in routes.keys() { for route in routes.keys() {
debug!("got route: {} gw {}", route.0, route.1);
self.cache_table.insert(*route, AtomicBool::new(false)); 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(()) Ok(())
} }
pub fn apply_system(&self) { pub fn apply_system(&self, if_idx: u32) {
debug!("applying system");
for route in &self.cache_table { for route in &self.cache_table {
let (net, gw) = route.key(); let (net, gw) = route.key();
debug!("route is {} gw {}", net, gw);
if !route.value().load(Ordering::Relaxed) { 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()); 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 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); error!("failed to parse cidr: {}, skipping", cidr);
return Err(SDLanError::IOError("failed to parse cidr".to_string())); 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 ipnet::Ipv4Net;
use sdlan_sn_rs::config::SDLAN_DEFAULT_TTL; use sdlan_sn_rs::config::SDLAN_DEFAULT_TTL;
use sdlan_sn_rs::utils::{ 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::io::{Error, ErrorKind};
use std::net::Ipv4Addr; use std::net::Ipv4Addr;
@ -15,13 +15,14 @@ use std::sync::Arc;
use tracing::{debug, error, info}; use tracing::{debug, error, info};
use wintun; use wintun;
use crate::{caculate_crc, get_edge};
use crate::network::{ 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::tcp::PacketType;
use crate::utils::mac_to_string; use crate::utils::mac_to_string;
use crate::{caculate_crc, get_edge};
use super::device::{DeviceConfig, Mode}; use super::device::{DeviceConfig, Mode};
use super::TunTapPacketHandler; use super::TunTapPacketHandler;
@ -34,6 +35,10 @@ pub struct Iface {
} }
impl Iface { impl Iface {
pub fn get_if_idx(&self) -> u32 {
self.if_idx
}
pub fn recv(&self, buf: &mut [u8]) -> std::io::Result<usize> { pub fn recv(&self, buf: &mut [u8]) -> std::io::Result<usize> {
let Ok(pkt) = self.session.receive_blocking() else { let Ok(pkt) = self.session.receive_blocking() else {
return Err(Error::new(ErrorKind::Other, "failed to receive")); 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) { if let Err(e) = set_dns(&self.name, network_domain, &ip, self.if_idx) {
error!("failed to set dns: {:?}", e); error!("failed to set dns: {:?}", e);
} else { } else {
error!("set dns ok"); debug!("set dns ok");
} }
node.route_table.apply_system(self.if_idx);
} }
} }
impl TunTapPacketHandler for Iface { impl TunTapPacketHandler for Iface {
async fn handle_packet_from_net(&self, data: &[u8]) -> std::io::Result<()> { async fn handle_packet_from_net(&self, data: &[u8]) -> std::io::Result<()> {
match Ethernet2Header::from_slice(&data) { match Ethernet2Header::from_slice(&data) {
Ok((hdr, rest)) => { Ok((hdr, rest)) => {
use etherparse::ether_type::ARP; use etherparse::ether_type::ARP;
@ -247,7 +252,6 @@ impl TunTapPacketHandler for Iface {
} }
} }
ARP_REPLY => { ARP_REPLY => {
debug!("mac {:?} is at {:?}", arp.shwaddr, from_ip.to_be_bytes()); debug!("mac {:?} is at {:?}", arp.shwaddr, from_ip.to_be_bytes());
if dest_ip == self_ip { if dest_ip == self_ip {
/* /*
@ -446,10 +450,7 @@ impl TunTapPacketHandler for Iface {
// Ok(()) // Ok(())
// } // }
async fn handle_packet_from_device( async fn handle_packet_from_device(&self, mut header: BytesMut) -> std::io::Result<()> {
&self,
mut header: BytesMut,
) -> std::io::Result<()> {
use etherparse::IpHeaders; use etherparse::IpHeaders;
let eee = get_edge(); let eee = get_edge();
@ -467,10 +468,8 @@ impl TunTapPacketHandler for Iface {
return Ok(()); return Ok(());
}; };
match net { match net {
NetSlice::Ipv4(ipv4) => { NetSlice::Ipv4(ipv4) => {
let dstip = u32::from_be_bytes(ipv4.header().destination()); let dstip = u32::from_be_bytes(ipv4.header().destination());
// let dstip = u32::from_be_bytes(ipv4hdr.0.destination); // let dstip = u32::from_be_bytes(ipv4hdr.0.destination);
debug!("packet dst ip: {:?}", ip_to_string(&dstip)); debug!("packet dst ip: {:?}", ip_to_string(&dstip));
@ -479,7 +478,9 @@ impl TunTapPacketHandler for Iface {
debug!("packet src ip: {:?}", ip_to_string(&src)); debug!("packet src ip: {:?}", ip_to_string(&src));
// packet should be sent to dev // packet should be sent to dev
debug!("got {} bytes from tun", data.len()); 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"); info!("dropping routed packet");
return Ok(()); return Ok(());
} }
@ -498,14 +499,19 @@ impl TunTapPacketHandler for Iface {
// should do the dns request // should do the dns request
// println!("request for dns"); // 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() // edge.udp_sock_for_dns.send_to()
return Ok(()); return Ok(());
} }
} }
_other => { _other => {}
}
} }
match eee.arp_table.get(dstip) { match eee.arp_table.get(dstip) {
@ -522,7 +528,6 @@ impl TunTapPacketHandler for Iface {
let crc = caculate_crc(&data); let crc = caculate_crc(&data);
header.unsplit(data); header.unsplit(data);
// packet.extend_from_slice(&etherheader.to_bytes()[..]); // packet.extend_from_slice(&etherheader.to_bytes()[..]);
// packet.extend_from_slice(&data); // packet.extend_from_slice(&data);
header.extend_from_slice(&crc.to_be_bytes()); header.extend_from_slice(&crc.to_be_bytes());
@ -554,38 +559,42 @@ impl TunTapPacketHandler for Iface {
} }
None => { None => {
header.unsplit(data); header.unsplit(data);
eee.arp_table.add_to_arp_wait_list(dstip, header);
debug!( debug!(
"find ip: {:?} => {:?}", "find ip: {:?} => {:?}",
src.to_be_bytes(), src.to_be_bytes(),
dstip.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; // let _ = eee.send_arp_request(dstip, dstip).await;
if eee.device_config.contains(&Ipv4Addr::from_bits(dstip)) { 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; let _ = eee.send_arp_request(dstip, dstip).await;
} else { } else {
debug!("try to lookup ip: {}", ip_to_string(&dstip));
if let Some((_, real_ip)) = eee.route_table.lookup(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 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(()) Ok(())
} }
/* /*
async fn handle_packet_from_device( async fn handle_packet_from_device(
&self, &self,
@ -717,7 +726,9 @@ fn create_wintun(path: &str, name: &str) -> Iface {
Err(_e) => wintun::Adapter::create(&wt, name, "Example", None) Err(_e) => wintun::Adapter::create(&wt, name, "Example", None)
.expect("failed to create tun adapter"), .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); // println!("idx = {}", idx);
let session = Arc::new(adapter.start_session(wintun::MAX_RING_CAPACITY).unwrap()); let session = Arc::new(adapter.start_session(wintun::MAX_RING_CAPACITY).unwrap());
Iface { Iface {
@ -737,7 +748,7 @@ pub fn get_install_channel() -> String {
"windows".to_owned() "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") let res = Command::new("ROUTE")
.arg("ADD") .arg("ADD")
.arg("100.100.100.100") .arg("100.100.100.100")
@ -769,11 +780,10 @@ pub fn set_dns(name: &str, _network_domain: &str, gw: &str, ifidx: u32) -> std::
Ok(()) Ok(())
} }
pub fn restore_dns() { pub fn restore_dns() {}
}
pub fn del_route(net: &Ipv4Net, gw: &Ipv4Addr) -> Result<()> { pub fn del_route(net: &Ipv4Net, gw: &Ipv4Addr) -> Result<()> {
error!("deleting route: {} gw {}", net, gw);
let mask = net.netmask().to_string(); let mask = net.netmask().to_string();
let network = net.network().to_string(); let network = net.network().to_string();
let res = Command::new("route") let res = Command::new("route")
@ -783,32 +793,54 @@ pub fn del_route(net: &Ipv4Net, gw: &Ipv4Addr) -> Result<()> {
.arg(gw.to_string()) .arg(gw.to_string())
.output()?; .output()?;
Ok(()) 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 mask = net.netmask().to_string();
let network = net.network().to_string(); let network = net.network().to_string();
let res = Command::new("route") match Command::new("route")
.arg("add") .arg("add")
.arg(network) .arg(network)
.arg("MASK")
.arg(mask) .arg(mask)
.arg(gw.to_string()) .arg(gw.to_string())
.output()?; .arg("if")
Ok(()) .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) { pub async fn arp_reply_arrived(edge: &Node, data: SdlArpResponse) {
debug!("got arp response: {:?}", data); debug!("got arp response: {:?}", data);
if data.target_mac.len() != 6 { if data.target_mac.len() != 6 {
// invalid target_mac // 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; return;
} }
let ip = data.target_ip; let ip = data.origin_ip;
let mac = data.target_mac.try_into().unwrap(); 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; edge.arp_table.arp_arrived(ip, mac).await;
} }

View File

@ -1,4 +1,3 @@
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use bytes::{Bytes, BytesMut}; use bytes::{Bytes, BytesMut};
@ -6,7 +5,7 @@ use dashmap::DashMap;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use sdlan_sn_rs::{ use sdlan_sn_rs::{
config::SDLAN_DEFAULT_TTL, 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}; use tracing::{debug, warn};
@ -14,8 +13,8 @@ use tracing::{debug, warn};
use tracing::error; use tracing::error;
use crate::{ use crate::{
network::{Node, RouteInfo, form_ethernet_packet, send_packet_to_net}, network::{form_ethernet_packet, send_packet_to_net, Node, RouteInfo},
pb::{SdlData, encode_to_udp_message}, pb::{encode_to_udp_message, SdlData},
tcp::PacketType, tcp::PacketType,
utils::mac_to_string, utils::mac_to_string,
}; };
@ -24,18 +23,17 @@ use super::get_edge;
pub const MAX_WAIT_PACKETS: usize = 100; 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 { pub trait TunTapPacketHandler {
async fn handle_packet_from_net(&self, data: &[u8]) -> std::io::Result<()>; async fn handle_packet_from_net(&self, data: &[u8]) -> std::io::Result<()>;
async fn handle_packet_from_device(&self, data: BytesMut) -> 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(); let eee = get_edge();
eee.route_table.clear_and_add_routes(routes)?; eee.route_table.clear_and_add_routes(routes)?;
eee.route_table.apply_system(); eee.route_table.apply_system(eee.device.get_if_idx());
Ok(()) Ok(())
} }
@ -149,7 +147,6 @@ pub fn get_dns_gateway(edge: &Node, payload: &[u8]) -> Option<String> {
Ok(p) => p, Ok(p) => p,
}; };
let mut target_dns: &str = ""; let mut target_dns: &str = "";
if !dns_packet.has_flags(simple_dns::PacketFlag::RESPONSE) && !dns_packet.questions.is_empty() { if !dns_packet.has_flags(simple_dns::PacketFlag::RESPONSE) && !dns_packet.questions.is_empty() {
let question = &dns_packet.questions[0]; let question = &dns_packet.questions[0];
@ -168,27 +165,55 @@ pub fn get_dns_gateway(edge: &Node, payload: &[u8]) -> Option<String> {
return None; 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) { match simple_dns::Packet::parse(layer7) {
Ok(mut dns) => { Ok(mut dns) => {
if !dns.has_flags(simple_dns::PacketFlag::RESPONSE) && !dns.questions.is_empty() { if !dns.has_flags(simple_dns::PacketFlag::RESPONSE) && !dns.questions.is_empty() {
let question = &dns.questions[0]; let question = &dns.questions[0];
let qname = question.qname.to_string(); let qname = question.qname.to_string();
if qname.ends_with(edge.network_domain.load().as_str()) { if qname.ends_with(edge.network_domain.load().as_str()) {
warn!("question 15353 for {} from {}:{} with transaction_id = {}", warn!(
qname, ip_to_string(&source_ip), source_port, dns.id()); "question 15353 for {} from {}:{} with transaction_id = {}",
qname,
ip_to_string(&source_ip),
source_port,
dns.id()
);
// should send to our socket // 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); error!("failed to send request to 15353: {}", e);
} }
} else { } else {
let origin_transaction_id = dns.id(); 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); dns.set_id(transaction_id);
warn!("question 223.5.5.5 for {} from {}:{} with transaction_id = {}", warn!(
qname, ip_to_string(&source_ip), source_port, dns.id()); "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 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); 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 futures_util::pin_mut;
use prost::Message; use prost::Message;
use quinn::SendStream; 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 sdlan_sn_rs::{
use tokio::{sync::mpsc::{Receiver, Sender, channel}, time::sleep}; 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 tokio_util::sync::CancellationToken;
use tracing::{debug, error, warn, info}; use tracing::{debug, error, info, warn};
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
use crate::network::{set_allow_routing, set_disallow_routing}; 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(); static GLOBAL_QUIC_HANDLE: OnceLock<ReadWriterHandle> = OnceLock::new();
@ -73,7 +103,7 @@ impl ReadWriterHandle {
to_tcp, to_tcp,
// on_connected, // on_connected,
// on_disconnected, // on_disconnected,
start_stop_chan start_stop_chan,
) )
.await .await
}); });
@ -106,7 +136,6 @@ pub fn get_quic_write_conn() -> &'static ReadWriterHandle {
} }
} }
async fn handle_tcp_message(msg: SdlanTcp) { async fn handle_tcp_message(msg: SdlanTcp) {
let edge = get_edge(); let edge = get_edge();
@ -138,18 +167,20 @@ async fn handle_tcp_message(msg: SdlanTcp) {
match ack.algorithm.to_ascii_lowercase().as_str() { match ack.algorithm.to_ascii_lowercase().as_str() {
"chacha20" => { "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)); // *edge.encryptor.write().unwrap() = MyEncryptor::ChaChao20(Chacha20Encryptor::new(key, ack.region_id));
} }
"aes" => { "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)); // *edge.encryptor.write().unwrap() = MyEncryptor::Aes(AesEncryptor::new(key));
} }
_other => { _other => {}
} }
}
/* /*
let Some(dev) = ack.dev_addr else { let Some(dev) = ack.dev_addr else {
@ -188,7 +219,8 @@ async fn handle_tcp_message(msg: SdlanTcp) {
edge.network_id.store(dev.network_id, Ordering::Relaxed); edge.network_id.store(dev.network_id, Ordering::Relaxed);
*/ */
// edge.device.reload_config(&edge.device_config, &dev.network_domain); // 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); edge.set_authorized(true);
@ -205,7 +237,6 @@ async fn handle_tcp_message(msg: SdlanTcp) {
return; return;
}; };
arp_reply_arrived(edge, res).await; arp_reply_arrived(edge, res).await;
return; return;
} }
@ -222,13 +253,10 @@ async fn handle_tcp_message(msg: SdlanTcp) {
break; break;
} }
let proto = policy.rules[start]; 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; start += 3;
infos.push(RuleFromServer{ infos.push(RuleFromServer { proto, port });
proto,
port,
});
} }
edge.rule_cache.set_identity_cache(identity, infos); edge.rule_cache.set_identity_cache(identity, infos);
@ -342,7 +370,6 @@ async fn handle_tcp_message(msg: SdlanTcp) {
} }
} }
async fn handle_tcp_command(edge: &Node, cmdprotobuf: &[u8]) { async fn handle_tcp_command(edge: &Node, cmdprotobuf: &[u8]) {
let Ok(cmd) = SdlCommand::decode(cmdprotobuf) else { let Ok(cmd) = SdlCommand::decode(cmdprotobuf) else {
error!("failed to decode SdlCommand"); error!("failed to decode SdlCommand");
@ -362,7 +389,10 @@ async fn handle_tcp_command(edge: &Node, cmdprotobuf: &[u8]) {
// std::process::exit(0); // std::process::exit(0);
if node.action == 0 { if node.action == 0 {
// stop // 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(); let mut config = load_configuration();
config.allow_routing = Some(false); config.allow_routing = Some(false);
let _ = store_configuration(&config); 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, pkt_id,
code: 0, code: 0,
message: "ok".to_owned(), 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]) { 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); debug!("unhandled event {:?}", other);
} }
} }
} }
pub fn init_quic_conn( pub fn init_quic_conn(
cancel: CancellationToken, cancel: CancellationToken,
addr: &str, addr: &str,
@ -472,8 +499,8 @@ pub fn init_quic_conn(
connecting_chan: Option<Sender<ConnectionInfo>>, connecting_chan: Option<Sender<ConnectionInfo>>,
ipv6_network_restarter: Option<Sender<bool>>, ipv6_network_restarter: Option<Sender<bool>>,
) )
// T2: Fn(SdlanTcp) -> F + Send + 'static, // T2: Fn(SdlanTcp) -> F + Send + 'static,
// F: Future<Output = ()> + Send, // F: Future<Output = ()> + Send,
{ {
let tcp_handle = ReadWriterHandle::new( let tcp_handle = ReadWriterHandle::new(
cancel, cancel,
@ -577,7 +604,10 @@ impl ReadWriteActor {
debug!("try connecting to {}", self.domain); 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, Ok(conn) => conn,
Err(e) => { Err(e) => {
error!("failed to connect: {}", e); error!("failed to connect: {}", e);
@ -589,7 +619,6 @@ impl ReadWriteActor {
continue; continue;
} }
return; return;
} }
}; };
@ -764,11 +793,8 @@ async fn on_connected_callback(local_ip: Option<IpAddr>, stream: &mut SendStream
// debug!("send register super: {:?}", register_super); // debug!("send register super: {:?}", register_super);
// let packet_id = edge.get_next_packet_id(); // let packet_id = edge.get_next_packet_id();
let data = encode_to_tcp_message( let data =
Some(register_super), encode_to_tcp_message(Some(register_super), PacketType::RegisterSuper as u8).unwrap();
PacketType::RegisterSuper as u8,
)
.unwrap();
if let Err(e) = stream.write(&data).await { if let Err(e) = stream.write(&data).await {
error!("failed to write to tcp: {}", e.to_string()); error!("failed to write to tcp: {}", e.to_string());
} }

View File

@ -17,7 +17,7 @@ struct IpTrie {
impl IpTrie { impl IpTrie {
fn new() -> Self { fn new() -> Self {
Self { Self {
root: TrieNode::default() root: TrieNode::default(),
} }
} }
@ -28,17 +28,16 @@ impl IpTrie {
let mut node = &mut self.root; let mut node = &mut self.root;
for i in 0..prefix_len { 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())); 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.prefix_len = prefix_len;
node.nexthop = Some(nexthop); 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 node = &self.root;
let mut best = None; let mut best = None;
@ -46,7 +45,8 @@ impl IpTrie {
if node.nexthop.is_some() { if node.nexthop.is_some() {
best = Some((node.prefix_len, node.nexthop.unwrap())); 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] { match &node.child[bit] {
Some(child) => { Some(child) => {
node = 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 { pub struct RouteTableTrie {
trie: ArcSwap<IpTrie>, trie: ArcSwap<IpTrie>,
} }
@ -70,7 +115,7 @@ pub struct RouteTableTrie {
impl RouteTableTrie { impl RouteTableTrie {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
trie: ArcSwap::new(Arc::new(IpTrie::default())) trie: ArcSwap::new(Arc::new(IpTrie::default())),
} }
} }