added exclusive_tcp, and error_report

This commit is contained in:
alex 2026-05-04 15:47:30 +08:00
parent a3977ba52a
commit 7767096909
10 changed files with 132 additions and 39 deletions

View File

@ -6,7 +6,7 @@ Wants=network.target
[Service] [Service]
Type=simple Type=simple
WorkingDirectory=/usr/local/punchnet WorkingDirectory=/usr/local/punchnet
ExecStart=/usr/local/punchnet/punchnet ExecStart=/usr/local/punchnet/punchnet start
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target

View File

@ -169,10 +169,23 @@ where T: Serialize + HMacCalculator,
}; };
// println!("status: {}", response.status()); // println!("status: {}", response.status());
let text = response.text().await.unwrap(); // let text = response.text().await.unwrap();
let text = match response.text().await {
Ok(text) => text,
Err(e) => {
return Err(SDLanError::IOError(format!("failed to get response text: {}", e)))
}
};
let data = match serde_json::from_str(&text) {
Ok(data) => data,
Err(e) => {
return Err(SDLanError::IOError(format!("failed to deserialize text: {}", e)))
}
};
// println!("got test: {}", text); // println!("got test: {}", text);
let data = serde_json::from_str(&text).unwrap(); // let data = serde_json::from_str(&text).unwrap();
// println!("response: {}", response.text().await.unwrap()); // println!("response: {}", response.text().await.unwrap());
// let Ok(data) = response.json().await else { // let Ok(data) = response.json().await else {

View File

@ -167,7 +167,7 @@ async fn daemonize_me(
println!("hostname = {:?}", hostname); println!("hostname = {:?}", hostname);
*/ */
let _ = run_sdlan( if let Err(e) = run_sdlan(
client_id, client_id,
mac, mac,
CommandLine { CommandLine {
@ -196,8 +196,11 @@ async fn daemonize_me(
server, server,
Some(self_host_name), Some(self_host_name),
None, None,
None,
) )
.await; .await {
panic!("failed to run_sdlan: {}", e.as_str());
};
let _ = rx.recv(); let _ = rx.recv();

View File

@ -17,7 +17,7 @@ pub use network::{async_main, init_edge, NodeConfig, restore_dns};
pub use network::{RouteInfo, set_route_from_net}; pub use network::{RouteInfo, set_route_from_net};
use sdlan_sn_rs::utils::{Mac, save_to_file}; use sdlan_sn_rs::utils::{Mac, save_to_file};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tokio::net::UdpSocket; use tokio::net::{TcpListener, UdpSocket};
use tokio::sync::mpsc::{channel, Sender}; use tokio::sync::mpsc::{channel, Sender};
use tokio_util::sync::CancellationToken; use tokio_util::sync::CancellationToken;
use tracing::{debug, error}; use tracing::{debug, error};
@ -59,13 +59,15 @@ pub async fn run_sdlan(
server_ip: String, server_ip: String,
hostname: Option<String>, hostname: Option<String>,
connecting_chan: Option<Sender<ConnectionInfo>>, // start_stop_sender: Sender<String>, connecting_chan: Option<Sender<ConnectionInfo>>,
// start_stop_receiver: Receiver<String>, // report error to
error_report_channel: Option<Sender<ErrorReport>>,
) -> Result<()> { ) -> Result<()> {
let (start_stop_sender, start_stop_chan) = channel(20); let (start_stop_sender, start_stop_chan) = channel(20);
// let edge_uuid = create_or_load_uuid(&format!("{}/.id", get_base_dir()), None)?; // let edge_uuid = create_or_load_uuid(&format!("{}/.id", get_base_dir()), None)?;
let node_conf = parse_config(edge_uuid, &args).await?; let node_conf = parse_config(edge_uuid, &args).await?;
let hostfile = format!("{}/.host", get_base_dir()); let hostfile = format!("{}/.host", get_base_dir());
let host = create_or_load_uuid(&hostfile, Some(8))?; let host = create_or_load_uuid(&hostfile, Some(8))?;
@ -76,7 +78,19 @@ pub async fn run_sdlan(
let sock_dns = Arc::new(UdpSocket::bind("0.0.0.0:0").await?); let sock_dns = Arc::new(UdpSocket::bind("0.0.0.0:0").await?);
let udp_sock_for_global_dns = Arc::new(UdpSocket::bind("0.0.0.0:0").await?); let udp_sock_for_global_dns = Arc::new(UdpSocket::bind("0.0.0.0:0").await?);
if let Err(e) = init_edge( let exclusive_tcp = match TcpListener::bind("127.0.0.1:7653").await {
Ok(tcp) => tcp,
Err(e) => {
if let Some(ref chan) = error_report_channel {
chan.send(ErrorReport { severity: ErrorSeverity::Panic, message: "bind tcp failed, is process already running?".to_string() }).await;
return Err(e.into());
} else {
panic!("new iface failed: {}", e.to_string());
}
}
};
init_edge(
// &args.token, // &args.token,
// &args.network_code, // &args.network_code,
&args, &args,
@ -91,11 +105,11 @@ pub async fn run_sdlan(
hostname, hostname,
server_ip, server_ip,
install_channel.to_owned(), install_channel.to_owned(),
error_report_channel,
exclusive_tcp,
) )
.await .await?;
{
panic!("failed to init edge: {:?}", e);
}
let _ = sender.send(true); let _ = sender.send(true);
debug!("edge inited"); debug!("edge inited");

View File

@ -12,7 +12,7 @@ use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU64, AtomicU8, Ordering};
use std::sync::{Arc, Mutex, RwLock}; use std::sync::{Arc, Mutex, RwLock};
use std::time::Duration; use std::time::Duration;
use tokio::io::AsyncReadExt; use tokio::io::AsyncReadExt;
use tokio::net::UdpSocket; use tokio::net::{TcpListener, UdpSocket};
use tokio::sync::mpsc::Sender; use tokio::sync::mpsc::Sender;
use tracing::{debug, error, warn}; use tracing::{debug, error, warn};
@ -25,8 +25,7 @@ use crate::quic::quic_init;
use crate::tcp::{get_quic_write_conn, NatType, PacketType, StunProbeAttr}; use crate::tcp::{get_quic_write_conn, NatType, PacketType, StunProbeAttr};
use crate::utils::Socket; use crate::utils::Socket;
use crate::{ use crate::{
get_base_dir, get_default_interface, CommandLine, ConnectionInfo, DNSMatcher, MyEncryptor, CommandLine, ConnectionInfo, DNSMatcher, ErrorReport, ErrorSeverity, MyEncryptor, RuleCache, get_base_dir, get_default_interface
RuleCache,
}; };
use sdlan_sn_rs::peer::{IpSubnet, V6Info}; use sdlan_sn_rs::peer::{IpSubnet, V6Info};
@ -57,6 +56,8 @@ pub async fn init_edge(
hostname: String, hostname: String,
server_ip: String, server_ip: String,
install_channel: String, install_channel: String,
error_report_channel: Option<Sender<ErrorReport>>,
exclusive_tcp: TcpListener,
) -> Result<()> { ) -> Result<()> {
// gen public key // gen public key
let rsa_path = format!("{}/.client", get_base_dir()); let rsa_path = format!("{}/.client", get_base_dir());
@ -108,6 +109,27 @@ pub async fn init_edge(
// TODO: set the sn's tcp socket // TODO: set the sn's tcp socket
// let tcpsock = TCPSocket::build("121.4.79.234:1234").await?; // let tcpsock = TCPSocket::build("121.4.79.234:1234").await?;
let tcp_pong = Arc::new(AtomicU64::new(0)); let tcp_pong = Arc::new(AtomicU64::new(0));
let mode = if cfg!(not(feature = "tun")) {
Mode::Tap
} else {
Mode::Tun
};
let iface = match new_iface("dev", mode) {
Ok(iface) => iface,
Err(e) => {
if let Some(ref chan) = error_report_channel {
chan.send(ErrorReport { severity: ErrorSeverity::Panic, message: e.to_string() }).await;
return Err(e.into());
} else {
panic!("new iface failed: {}", e.to_string());
}
},
};
let edge = Node::new( let edge = Node::new(
mac, mac,
pubkey, pubkey,
@ -128,6 +150,9 @@ pub async fn init_edge(
server_ip, server_ip,
install_channel, install_channel,
args.take_dns, args.take_dns,
error_report_channel,
iface,
exclusive_tcp,
); );
edge.route_table edge.route_table
@ -288,9 +313,13 @@ pub struct Node {
nat_cookie: AtomicU32, nat_cookie: AtomicU32,
error_report_channel: Option<Sender<ErrorReport>>,
//cookie_match: DashMap<u32, oneshot::Sender<SdlStunProbeReply>>, //cookie_match: DashMap<u32, oneshot::Sender<SdlStunProbeReply>>,
pub cookie_match: Queryer, pub cookie_match: Queryer,
// packet_id_match: DashMap<u32, oneshot::Sender<RegisterSuperFeedback>>, // packet_id_match: DashMap<u32, oneshot::Sender<RegisterSuperFeedback>>,
exclusive_tcp: TcpListener,
} }
unsafe impl Sync for Node {} unsafe impl Sync for Node {}
@ -442,12 +471,11 @@ impl Node {
server_ip: String, server_ip: String,
install_channel: String, install_channel: String,
take_over_dns: bool, take_over_dns: bool,
// 是否需要上报错误信息
error_report_info: Option<Sender<ErrorReport>>,
virtual_iface: Iface,
tcp_listener: TcpListener,
) -> Self { ) -> Self {
let mode = if cfg!(not(feature = "tun")) {
Mode::Tap
} else {
Mode::Tun
};
Self { Self {
#[cfg(any(feature = "tun", target_os = "windows"))] #[cfg(any(feature = "tun", target_os = "windows"))]
@ -485,7 +513,7 @@ impl Node {
nat_type: Mutex::new(NatType::Blocked), nat_type: Mutex::new(NatType::Blocked),
device_config: DeviceConfig::new(mac, mtu), device_config: DeviceConfig::new(mac, mtu),
device: new_iface("dev", mode), device: virtual_iface,
authorized: AtomicBool::new(false), authorized: AtomicBool::new(false),
// encrypt_key: RwLock::new(Arc::new(Vec::new())), // encrypt_key: RwLock::new(Arc::new(Vec::new())),
@ -519,9 +547,11 @@ impl Node {
// packet_id_match: DashMap::new(), // packet_id_match: DashMap::new(),
nat_cookie: AtomicU32::new(1), nat_cookie: AtomicU32::new(1),
cookie_match: Queryer::new(), cookie_match: Queryer::new(),
error_report_channel: error_report_info,
server_ip, server_ip,
install_channel, install_channel,
take_over_dns, take_over_dns,
exclusive_tcp: tcp_listener,
} }
} }

View File

@ -24,7 +24,7 @@ use std::ptr::null_mut;
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use sdlan_sn_rs::utils::Result; use sdlan_sn_rs::utils::Result;
use std::io::{BufRead, BufReader, Read, Write}; use std::io::{BufRead, BufReader, ErrorKind, Read, Write};
use std::os::fd::AsRawFd; use std::os::fd::AsRawFd;
use std::process::Command; use std::process::Command;
@ -66,12 +66,13 @@ pub struct Iface {
has_resolvectl: bool, has_resolvectl: bool,
} }
pub fn new_iface(tunname: &str, mode: Mode) -> Iface { pub fn new_iface(tunname: &str, mode: Mode) -> std::io::Result<Iface> {
match Iface::without_packet_info(tunname, mode) { match Iface::without_packet_info(tunname, mode) {
Err(e) => { Err(e) => {
panic!("failed to create tun: {}", e.as_str()); error!("failed to create tun: {}", e.as_str());
Err(std::io::Error::new(ErrorKind::Other, "failed to create virtial device, is run with root?"))
} }
Ok(iface) => iface, Ok(iface) => Ok(iface),
} }
} }

View File

@ -55,10 +55,12 @@ impl Iface {
} }
pub fn send(&self, content: &[u8]) -> std::io::Result<usize> { pub fn send(&self, content: &[u8]) -> std::io::Result<usize> {
let mut pkt = self let Ok(mut pkt) = self
.session .session
.allocate_send_packet(content.len() as u16) .allocate_send_packet(content.len() as u16) else {
.unwrap(); error!("failed to allocate send packet");
return Err(std::io::Error::new(std::io::ErrorKind::Other, "failed to allocate send packet"));
};
let buf: &mut [u8] = pkt.bytes_mut(); let buf: &mut [u8] = pkt.bytes_mut();
buf.copy_from_slice(content); buf.copy_from_slice(content);
self.session.send_packet(pkt); self.session.send_packet(pkt);
@ -727,28 +729,35 @@ impl TunTapPacketHandler for Iface {
}*/ }*/
} }
fn create_wintun(path: &str, name: &str) -> Iface { fn create_wintun(path: &str, name: &str) -> std::io::Result<Iface> {
let wt = unsafe { wintun::load_from_path(path) }.expect("failed to load wintun"); let wt = unsafe { wintun::load_from_path(path) }.expect("failed to load wintun");
let adapter = match wintun::Adapter::open(&wt, name) { let adapter = match wintun::Adapter::open(&wt, name) {
Ok(a) => a, Ok(a) => a,
Err(_e) => wintun::Adapter::create(&wt, name, "Example", None) Err(_e) => {
.expect("failed to create tun adapter"), let Ok(adapt) = wintun::Adapter::create(&wt, name, "Punchnet", None) else {
return Err(std::io::Error::new(std::io::ErrorKind::Other, "failed to create Punch adapter"));
};
adapt
}
}; };
let idx = adapter let idx = adapter
.get_adapter_index() .get_adapter_index()
.expect("failed to 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 Ok(sess) = adapter.start_session(wintun::MAX_RING_CAPACITY) else {
Iface { return Err(std::io::Error::new(std::io::ErrorKind::Other, "failed to start session, maybe one process is running, or not running with admin?"));
};
let session = Arc::new(sess);
Ok(Iface {
if_idx: idx, if_idx: idx,
_adapter: adapter, _adapter: adapter,
session, session,
name: name.to_owned(), name: name.to_owned(),
} })
} }
pub fn new_iface(name: &str, _mode: Mode) -> Iface { pub fn new_iface(name: &str, _mode: Mode) -> std::io::Result<Iface> {
create_wintun("./wintun.dll", name) create_wintun("./wintun.dll", name)
// Ok(Box::new(create_wintun("/path/to/file"))) // Ok(Box::new(create_wintun("/path/to/file")))
} }

View File

@ -147,6 +147,8 @@ pub fn load_private_key_from_pem(path: impl AsRef<Path>) -> Option<PrivateKeyDer
return None; return None;
}; };
let mut reader = BufReader::new(file); let mut reader = BufReader::new(file);
let key = private_key(&mut reader).unwrap(); if let Ok(key) = private_key(&mut reader) {
key return key
}
None
} }

17
src/utils/error_report.rs Normal file
View File

@ -0,0 +1,17 @@
use serde::Serialize;
#[derive(Debug, Serialize)]
#[repr(u8)]
pub enum ErrorSeverity {
Panic,
Error,
Warning,
Info,
Log,
}
#[derive(Debug, Serialize)]
pub struct ErrorReport {
pub severity: ErrorSeverity,
pub message: String,
}

View File

@ -4,6 +4,7 @@ mod encrypter;
mod system_action; mod system_action;
mod file_configuration; mod file_configuration;
mod dns; mod dns;
mod error_report;
use std::{fs::OpenOptions, io::Write, net::Ipv4Addr, path::Path}; use std::{fs::OpenOptions, io::Write, net::Ipv4Addr, path::Path};
use tracing::error; use tracing::error;
@ -13,6 +14,7 @@ pub use command::*;
pub use acl_session::*; pub use acl_session::*;
pub use system_action::*; pub use system_action::*;
pub use dns::*; pub use dns::*;
pub use error_report::*;
mod socks; mod socks;
use rand::Rng; use rand::Rng;
@ -52,7 +54,9 @@ pub fn ip_string_to_u32(ip: &str) -> Result<u32> {
pub fn get_access_token() -> Option<CachedLoginInfo> { pub fn get_access_token() -> Option<CachedLoginInfo> {
let path = format!("{}/.access_token", get_base_dir()); let path = format!("{}/.access_token", get_base_dir());
if let Ok(content) = std::fs::read(&path) { if let Ok(content) = std::fs::read(&path) {
let data = serde_json::from_slice(&content).unwrap(); let Ok(data) = serde_json::from_slice(&content) else {
return None;
};
return Some(data); return Some(data);
} }
None None