diff --git a/punchnet.service b/punchnet.service index 4570f26..7f3d664 100644 --- a/punchnet.service +++ b/punchnet.service @@ -6,7 +6,7 @@ Wants=network.target [Service] Type=simple WorkingDirectory=/usr/local/punchnet -ExecStart=/usr/local/punchnet/punchnet +ExecStart=/usr/local/punchnet/punchnet start [Install] WantedBy=multi-user.target diff --git a/src/bin/punchnet/api/mod.rs b/src/bin/punchnet/api/mod.rs index fceebcc..e9c6aec 100644 --- a/src/bin/punchnet/api/mod.rs +++ b/src/bin/punchnet/api/mod.rs @@ -169,10 +169,23 @@ where T: Serialize + HMacCalculator, }; // 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); - let data = serde_json::from_str(&text).unwrap(); + // let data = serde_json::from_str(&text).unwrap(); // println!("response: {}", response.text().await.unwrap()); // let Ok(data) = response.json().await else { diff --git a/src/bin/punchnet/main.rs b/src/bin/punchnet/main.rs index 0711f99..c40a995 100755 --- a/src/bin/punchnet/main.rs +++ b/src/bin/punchnet/main.rs @@ -167,7 +167,7 @@ async fn daemonize_me( println!("hostname = {:?}", hostname); */ - let _ = run_sdlan( + if let Err(e) = run_sdlan( client_id, mac, CommandLine { @@ -196,8 +196,11 @@ async fn daemonize_me( server, Some(self_host_name), None, + None, ) - .await; + .await { + panic!("failed to run_sdlan: {}", e.as_str()); + }; let _ = rx.recv(); diff --git a/src/lib.rs b/src/lib.rs index 0f487bf..ec1de87 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,7 +17,7 @@ pub use network::{async_main, init_edge, NodeConfig, restore_dns}; pub use network::{RouteInfo, set_route_from_net}; use sdlan_sn_rs::utils::{Mac, save_to_file}; use serde::{Deserialize, Serialize}; -use tokio::net::UdpSocket; +use tokio::net::{TcpListener, UdpSocket}; use tokio::sync::mpsc::{channel, Sender}; use tokio_util::sync::CancellationToken; use tracing::{debug, error}; @@ -59,13 +59,15 @@ pub async fn run_sdlan( server_ip: String, hostname: Option, - connecting_chan: Option>, // start_stop_sender: Sender, - // start_stop_receiver: Receiver, + connecting_chan: Option>, + // report error to + error_report_channel: Option>, ) -> Result<()> { let (start_stop_sender, start_stop_chan) = channel(20); // let edge_uuid = create_or_load_uuid(&format!("{}/.id", get_base_dir()), None)?; let node_conf = parse_config(edge_uuid, &args).await?; + let hostfile = format!("{}/.host", get_base_dir()); 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 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.network_code, &args, @@ -91,11 +105,11 @@ pub async fn run_sdlan( hostname, server_ip, install_channel.to_owned(), + error_report_channel, + exclusive_tcp, ) - .await - { - panic!("failed to init edge: {:?}", e); - } + .await?; + let _ = sender.send(true); debug!("edge inited"); diff --git a/src/network/node.rs b/src/network/node.rs index 94fde07..c3348cc 100755 --- a/src/network/node.rs +++ b/src/network/node.rs @@ -12,7 +12,7 @@ use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU64, AtomicU8, Ordering}; use std::sync::{Arc, Mutex, RwLock}; use std::time::Duration; use tokio::io::AsyncReadExt; -use tokio::net::UdpSocket; +use tokio::net::{TcpListener, UdpSocket}; use tokio::sync::mpsc::Sender; 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::utils::Socket; use crate::{ - get_base_dir, get_default_interface, CommandLine, ConnectionInfo, DNSMatcher, MyEncryptor, - RuleCache, + CommandLine, ConnectionInfo, DNSMatcher, ErrorReport, ErrorSeverity, MyEncryptor, RuleCache, get_base_dir, get_default_interface }; use sdlan_sn_rs::peer::{IpSubnet, V6Info}; @@ -57,6 +56,8 @@ pub async fn init_edge( hostname: String, server_ip: String, install_channel: String, + error_report_channel: Option>, + exclusive_tcp: TcpListener, ) -> Result<()> { // gen public key let rsa_path = format!("{}/.client", get_base_dir()); @@ -108,6 +109,27 @@ pub async fn init_edge( // TODO: set the sn's tcp socket // let tcpsock = TCPSocket::build("121.4.79.234:1234").await?; 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( mac, pubkey, @@ -128,6 +150,9 @@ pub async fn init_edge( server_ip, install_channel, args.take_dns, + error_report_channel, + iface, + exclusive_tcp, ); edge.route_table @@ -288,9 +313,13 @@ pub struct Node { nat_cookie: AtomicU32, + error_report_channel: Option>, + //cookie_match: DashMap>, pub cookie_match: Queryer, // packet_id_match: DashMap>, + + exclusive_tcp: TcpListener, } unsafe impl Sync for Node {} @@ -442,12 +471,11 @@ impl Node { server_ip: String, install_channel: String, take_over_dns: bool, + // 是否需要上报错误信息 + error_report_info: Option>, + virtual_iface: Iface, + tcp_listener: TcpListener, ) -> Self { - let mode = if cfg!(not(feature = "tun")) { - Mode::Tap - } else { - Mode::Tun - }; Self { #[cfg(any(feature = "tun", target_os = "windows"))] @@ -485,7 +513,7 @@ impl Node { nat_type: Mutex::new(NatType::Blocked), device_config: DeviceConfig::new(mac, mtu), - device: new_iface("dev", mode), + device: virtual_iface, authorized: AtomicBool::new(false), // encrypt_key: RwLock::new(Arc::new(Vec::new())), @@ -519,9 +547,11 @@ impl Node { // packet_id_match: DashMap::new(), nat_cookie: AtomicU32::new(1), cookie_match: Queryer::new(), + error_report_channel: error_report_info, server_ip, install_channel, take_over_dns, + exclusive_tcp: tcp_listener, } } diff --git a/src/network/tun_linux.rs b/src/network/tun_linux.rs index 195d281..409211c 100755 --- a/src/network/tun_linux.rs +++ b/src/network/tun_linux.rs @@ -24,7 +24,7 @@ use std::ptr::null_mut; use std::sync::atomic::Ordering; 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::process::Command; @@ -66,12 +66,13 @@ pub struct Iface { has_resolvectl: bool, } -pub fn new_iface(tunname: &str, mode: Mode) -> Iface { +pub fn new_iface(tunname: &str, mode: Mode) -> std::io::Result { match Iface::without_packet_info(tunname, mode) { 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), } } diff --git a/src/network/tun_win.rs b/src/network/tun_win.rs index eeeaf3e..0961f27 100755 --- a/src/network/tun_win.rs +++ b/src/network/tun_win.rs @@ -55,10 +55,12 @@ impl Iface { } pub fn send(&self, content: &[u8]) -> std::io::Result { - let mut pkt = self + let Ok(mut pkt) = self .session - .allocate_send_packet(content.len() as u16) - .unwrap(); + .allocate_send_packet(content.len() as u16) else { + 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(); buf.copy_from_slice(content); 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 { let wt = unsafe { wintun::load_from_path(path) }.expect("failed to load wintun"); let adapter = match wintun::Adapter::open(&wt, name) { Ok(a) => a, - Err(_e) => wintun::Adapter::create(&wt, name, "Example", None) - .expect("failed to create tun adapter"), + Err(_e) => { + 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 .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 { + let Ok(sess) = adapter.start_session(wintun::MAX_RING_CAPACITY) else { + 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, _adapter: adapter, session, name: name.to_owned(), - } + }) } -pub fn new_iface(name: &str, _mode: Mode) -> Iface { +pub fn new_iface(name: &str, _mode: Mode) -> std::io::Result { create_wintun("./wintun.dll", name) // Ok(Box::new(create_wintun("/path/to/file"))) } diff --git a/src/quic/mod.rs b/src/quic/mod.rs index b49bf80..3979c2e 100644 --- a/src/quic/mod.rs +++ b/src/quic/mod.rs @@ -147,6 +147,8 @@ pub fn load_private_key_from_pem(path: impl AsRef) -> Option Result { pub fn get_access_token() -> Option { let path = format!("{}/.access_token", get_base_dir()); 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); } None