From 5136e9427b32542584abeb8a31b233278c0b7ba5 Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 14 Apr 2026 23:34:46 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0dns=E8=A7=A3=E6=9E=90?= =?UTF-8?q?=EF=BC=8C=E5=A6=82=E6=9E=9Cdns=E6=98=AFpunchsky.com(punchnet?= =?UTF-8?q?=E5=86=85=E9=83=A8=E7=9A=84=E5=9F=9F=E5=90=8D),=E5=B0=B1?= =?UTF-8?q?=E8=BD=AC=E5=8F=91=E7=BB=9915353=E7=AB=AF=E5=8F=A3=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=EF=BC=9B=E5=85=B6=E4=BB=96=E7=9A=84=EF=BC=8C=E5=B0=B1?= =?UTF-8?q?=E7=9B=B4=E6=8E=A5=E8=BD=AC=E5=8F=91=E7=BB=99ali=20dns=20223.5.?= =?UTF-8?q?5.5:53=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 200 +++--------------------------------- Cargo.toml | 2 +- src/bin/punchnet/api/mod.rs | 9 +- src/bin/punchnet/main.rs | 4 +- src/lib.rs | 6 +- src/network/async_main.rs | 38 ++++++- src/network/node.rs | 29 +++++- src/network/tun_linux.rs | 169 +++++++++++++++++++++++++++--- src/network/tuntap.rs | 70 ++++++++++++- src/tcp/quic.rs | 2 +- src/utils/dns.rs | 47 +++++++++ src/utils/mod.rs | 3 + 12 files changed, 362 insertions(+), 217 deletions(-) create mode 100644 src/utils/dns.rs diff --git a/Cargo.lock b/Cargo.lock index 11cd6be..9c93f09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -149,15 +149,6 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" -[[package]] -name = "aok" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a8746a6637032084d12397dcd4b1f93d7c5e27dab4a2abe37515e5dadb7cdad" -dependencies = [ - "anyhow", -] - [[package]] name = "ar" version = "0.9.0" @@ -284,15 +275,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "boxleak" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "313d0a9cc1832e6636eec848805ab5471a546dc68dcfc058eea4d4602892cf64" -dependencies = [ - "aok", -] - [[package]] name = "bumpalo" version = "3.20.2" @@ -402,12 +384,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" -[[package]] -name = "cfg_aliases" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" - [[package]] name = "cfg_aliases" version = "0.2.1" @@ -462,15 +438,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "citer" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4fe42a458d9c1b72d540bb4bb0226bcfc2136c53b4407af5e23c9f7532f3ea" -dependencies = [ - "aok", -] - [[package]] name = "clap" version = "2.34.0" @@ -535,17 +502,6 @@ dependencies = [ "cc", ] -[[package]] -name = "coarsetime" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e58eb270476aa4fc7843849f8a35063e8743b4dbcdf6dd0f8ea0886980c204c2" -dependencies = [ - "libc", - "wasix", - "wasm-bindgen", -] - [[package]] name = "colorchoice" version = "1.0.5" @@ -828,18 +784,6 @@ dependencies = [ "windows-sys 0.60.2", ] -[[package]] -name = "dns_parse" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3943bb4aeaf3b6b8f9b8a8fa04609423ee8ab803e81c55385a18a7f86da339a9" -dependencies = [ - "bytes", - "hex", - "idns", - "thiserror 2.0.18", -] - [[package]] name = "dotenvy" version = "0.15.7" @@ -931,19 +875,6 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" -[[package]] -name = "expire_cache" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d65c4482fb3725e7d25768dd33864b29dcb1f9ad365742649a8eae8b6bec43ed" -dependencies = [ - "boxleak", - "papaya", - "parking_lot", - "sendptr", - "tokio", -] - [[package]] name = "fastbloom" version = "0.14.1" @@ -1528,22 +1459,6 @@ dependencies = [ "icu_properties", ] -[[package]] -name = "idns" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45ddb9b2206e9ff4b548671e4372986ca71f90efbef3d74c3e9c5893c7eec869" -dependencies = [ - "expire_cache", - "ip_set", - "log", - "papaya", - "pick_fast", - "race", - "static_init", - "ts_", -] - [[package]] name = "indexmap" version = "2.13.0" @@ -1566,12 +1481,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "ip_set" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33f71689e048d8568faba23fdc3a0822cd10738515b1c0b3851d84221663fec5" - [[package]] name = "ipnet" version = "2.12.0" @@ -1969,16 +1878,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" -[[package]] -name = "papaya" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "997ee03cd38c01469a7046643714f0ad28880bcb9e6679ff0666e24817ca19b7" -dependencies = [ - "equivalent", - "seize", -] - [[package]] name = "parking_lot" version = "0.12.5" @@ -2033,17 +1932,6 @@ dependencies = [ "indexmap", ] -[[package]] -name = "pick_fast" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8e330233974b83cda2e28df3ddf3e0d1675f1d4496f031e00a7a4a0b67d0506" -dependencies = [ - "citer", - "fastrand", - "log", -] - [[package]] name = "pin-project-lite" version = "0.2.17" @@ -2266,7 +2154,6 @@ dependencies = [ "daemonize", "dashmap 6.1.0", "dns-lookup", - "dns_parse", "etherparse", "futures-util", "hex", @@ -2291,6 +2178,7 @@ dependencies = [ "sdlan-sn-rs", "serde", "serde_json", + "simple-dns", "structopt", "tokio", "tokio-util", @@ -2312,7 +2200,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ "bytes", - "cfg_aliases 0.2.1", + "cfg_aliases", "pin-project-lite", "quinn-proto", "quinn-udp", @@ -2354,7 +2242,7 @@ version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" dependencies = [ - "cfg_aliases 0.2.1", + "cfg_aliases", "libc", "once_cell", "socket2", @@ -2383,17 +2271,6 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" -[[package]] -name = "race" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402085c832dd003de54bfa3b728c8b4b69632dc32a402c0c70cae8361bc2ec79" -dependencies = [ - "coarsetime", - "futures", - "tokio", -] - [[package]] name = "rand" version = "0.8.5" @@ -2815,28 +2692,12 @@ dependencies = [ "libc", ] -[[package]] -name = "seize" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b55fb86dfd3a2f5f76ea78310a88f96c4ea21a3031f8d212443d56123fd0521" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - [[package]] name = "semver" version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" -[[package]] -name = "sendptr" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ada566c72d62f4c53e5d0e593f4bab893dfb7d14b505a130b148189928f0988" - [[package]] name = "serde" version = "1.0.228" @@ -2975,6 +2836,15 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +[[package]] +name = "simple-dns" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df350943049174c4ae8ced56c604e28270258faec12a6a48637a7655287c9ce0" +dependencies = [ + "bitflags 2.11.0", +] + [[package]] name = "siphasher" version = "1.0.2" @@ -3228,34 +3098,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" -[[package]] -name = "static_init" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bae1df58c5fea7502e8e352ec26b5579f6178e1fdb311e088580c980dee25ed" -dependencies = [ - "bitflags 1.3.2", - "cfg_aliases 0.2.1", - "libc", - "parking_lot", - "parking_lot_core", - "static_init_macro", - "winapi", -] - -[[package]] -name = "static_init_macro" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1389c88ddd739ec6d3f8f83343764a0e944cd23cfbf126a9796a714b0b6edd6f" -dependencies = [ - "cfg_aliases 0.1.1", - "memchr", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "stringprep" version = "0.1.5" @@ -3721,15 +3563,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "ts_" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d4270cf460c46e2cafb448d9abebc506dff81e15148f19b2fc97686bfe8d4f" -dependencies = [ - "coarsetime", -] - [[package]] name = "typenum" version = "1.19.0" @@ -3917,15 +3750,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" -[[package]] -name = "wasix" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1757e0d1f8456693c7e5c6c629bdb54884e032aa0bb53c155f6a39f94440d332" -dependencies = [ - "wasi", -] - [[package]] name = "wasm-bindgen" version = "0.2.114" diff --git a/Cargo.toml b/Cargo.toml index 4b8fd8f..a872477 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,7 @@ ahash = "0.8.12" ipnet = "2.12.0" arc-swap = "1.9.0" rustls-native-certs = "0.8.3" -dns_parse = "0.1.2" +simple-dns = "0.11.2" # rolling-file = { path = "../rolling-file" } [target.'cfg(unix)'.dependencies] diff --git a/src/bin/punchnet/api/mod.rs b/src/bin/punchnet/api/mod.rs index d0e7946..137626f 100644 --- a/src/bin/punchnet/api/mod.rs +++ b/src/bin/punchnet/api/mod.rs @@ -81,6 +81,11 @@ pub struct LoginResponse { pub data: Option, } +#[derive(Debug, Deserialize)] +pub struct NetworkListInfo { + pub network_id: u32, + pub network_name: String, +} #[derive(Debug, Deserialize)] pub struct LoginData { @@ -90,7 +95,8 @@ pub struct LoginData { pub audit: u32, pub network_id: u32, pub network_name: String, - // pub network_domain: String, + pub network_domain: String, + pub my_network_list: Vec, // pub exit_node: Vec, } @@ -125,6 +131,7 @@ where T: Serialize + HMacCalculator, // println!("status: {}", response.status()); let text = response.text().await.unwrap(); + println!("got test: {}", text); let data = serde_json::from_str(&text).unwrap(); // println!("response: {}", response.text().await.unwrap()); diff --git a/src/bin/punchnet/main.rs b/src/bin/punchnet/main.rs index 63fb722..ad51d1d 100755 --- a/src/bin/punchnet/main.rs +++ b/src/bin/punchnet/main.rs @@ -101,6 +101,7 @@ fn parse_login_result(res: Result) -> LoginData { audit: data.audit, network_id: data.network_id, network_name: data.network_name.clone(), + network_domain: data.network_domain.clone(), }) { eprintln!("failed to save access_token"); } @@ -226,7 +227,7 @@ async fn daemonize_me( remembered.access_token.clone(), // String::new(), remembered.network_id, - &"".to_owned(), + &remembered.network_domain, ip_net, connect_info.mask_len, connect_info.identity_id, @@ -460,6 +461,7 @@ fn run_it(cmd: CommandLineInput2, client_id: String, allow_routing: bool, mac: M audit: data.audit, network_id: data.network_id, network_name: data.network_name, + network_domain: data.network_domain, }); } diff --git a/src/lib.rs b/src/lib.rs index 1cc6e88..f609c2e 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -73,7 +73,8 @@ pub async fn run_sdlan( let hostname = hostname.unwrap_or(host); let _ = save_to_file(&hostfile, &hostname); - let sock = 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?); if let Err(e) = init_edge( // &args.token, @@ -85,7 +86,8 @@ pub async fn run_sdlan( start_stop_sender, // args.mtu, connecting_chan.clone(), - sock, + sock_dns, + udp_sock_for_global_dns, hostname, server_ip, install_channel.to_owned(), diff --git a/src/network/async_main.rs b/src/network/async_main.rs index aefdab9..87fafe1 100755 --- a/src/network/async_main.rs +++ b/src/network/async_main.rs @@ -11,8 +11,9 @@ use crate::tcp::{init_quic_conn, send_stun_request}; use crate::utils::{send_to_sock, CommandLine}; use crate::{ConnectionInfo}; use bytes::BytesMut; +use etherparse::{PacketBuilder, SlicedPacket}; use sdlan_sn_rs::peer::{SdlanSock}; -use sdlan_sn_rs::utils::{get_current_timestamp, is_multi_broadcast}; +use sdlan_sn_rs::utils::{get_current_timestamp, ip_to_string, is_multi_broadcast}; use sdlan_sn_rs::utils::{Mac, Result}; use tokio::net::{UdpSocket}; use tokio::sync::mpsc::{channel, Receiver, Sender}; @@ -21,7 +22,7 @@ use tokio_util::sync::CancellationToken; use super::{Node, StartStopInfo}; use crate::utils::Socket; -use tracing::{debug, error}; +use tracing::{debug, error, warn}; pub async fn async_main( args: CommandLine, @@ -224,12 +225,45 @@ async fn loop_tap(eee: &'static Node, cancel: CancellationToken) { drop(rx); break; } + global_reply_global = receive_dns_reply(&eee.udp_sock_for_global_dns) => { + // global reply, only dns payload + if let Some(data) = global_reply_global { + if let Ok(mut dns) = simple_dns::Packet::parse(&data) { + let transaction_id = dns.id(); + if let Some((ip, port, origin_transaction_id)) = eee.dns_matcher.get_client_info(transaction_id) { + warn!("got dns reply from global 223.5.5.5: {:?}, will send to {}:{}", + data, ip_to_string(&ip), port); + + let dstmac = eee.device_config.get_mac(); + let srcmac = eee.device_config.dns_mac; + + dns.set_id(origin_transaction_id); + let builder = PacketBuilder::ethernet2(srcmac, dstmac) + .ipv4([100, 100, 100, 100], ip.to_be_bytes(), 64) + .udp(53, port); + + let new_dns_resp = dns.build_bytes_vec().unwrap(); + let mut response_packet = Vec::with_capacity(builder.size(new_dns_resp.len())); + if let Ok(_) = builder.write(&mut response_packet, &new_dns_resp) { + warn!("will send to tun with packet: {:?}", response_packet); + if let Err(_e) = eee.device.handle_packet_from_net(&response_packet).await { + error!("failed to write dns packet to device"); + } + } else { + error!("failed to write dns body"); + } + + } + } + } + } reply = receive_dns_reply(&eee.udp_sock_for_dns) => { if reply.is_none() { drop(rx); break; } let reply = reply.unwrap(); + warn!("got packet from 15353: {:?}", reply); let dstmac = eee.device_config.get_mac(); let srcmac = eee.device_config.dns_mac; let mut packet = Vec::with_capacity(14+reply.len()); diff --git a/src/network/node.rs b/src/network/node.rs index 1acbee1..cb7973a 100755 --- a/src/network/node.rs +++ b/src/network/node.rs @@ -17,7 +17,7 @@ use tracing::{debug, error, warn}; use crate::network::{ArpTable, RouteTable2}; use crate::quic::quic_init; -use crate::{CommandLine, ConnectionInfo, MyEncryptor, RuleCache, get_base_dir}; +use crate::{CommandLine, ConnectionInfo, DNSMatcher, MyEncryptor, RuleCache, get_base_dir}; use crate::pb::{ SdlArpRequest, SdlEmpty, SdlStunProbe, SdlStunProbeReply, encode_to_tcp_message, encode_to_udp_message }; @@ -48,6 +48,7 @@ pub async fn init_edge( // mtu: u32, connecting_chan: Option>, udpsock_for_dns: Arc, + udp_sock_for_global_dns: Arc, hostname: String, server_ip: String, install_channel: String @@ -97,13 +98,23 @@ pub async fn init_edge( connecting_chan, hostname, udpsock_for_dns, + udp_sock_for_global_dns, server_ip, install_channel, ); edge.route_table.parse_and_add_route(&args.route_file, &args.route_str); + let matcher = Arc::clone(&edge.dns_matcher); + do_init_edge(edge)?; + tokio::spawn(async move { + loop { + tokio::time::sleep(Duration::from_secs(10)).await; + matcher.retain(); + } + }); + Ok(()) } @@ -172,7 +183,7 @@ pub struct Node { pub encryptor: ArcSwap, pub network_id: AtomicU32, - pub network_domain: RwLock, + pub network_domain: ArcSwap, pub identity_id: IdentityID, @@ -190,6 +201,9 @@ pub struct Node { pub quic_endpoint: Endpoint, pub udp_sock_for_dns: Arc, + pub udp_sock_for_global_dns: Arc, + pub dns_matcher: Arc, + pub server_ip: String, pub tcp_pong: Arc, @@ -288,7 +302,8 @@ impl Node { // self.device_config.ip.net_bit_len.store(ip_net_bit_len, Ordering::Relaxed); // *self.device_config.mac.write().unwrap() = create_or_load_mac(); self.network_id.store(network_id, Ordering::Relaxed); - self.network_domain.write().unwrap().clone_from(network_domain); + self.network_domain.store(Arc::new(network_domain.clone())); + // self.network_domain.write().unwrap().clone_from(network_domain); // self.network_domain = network_domain; self.identity_id.store(identity_id); @@ -332,7 +347,8 @@ impl Node { } // *self.device_config.mac.write().unwrap() = create_or_load_mac(); self.network_id.store(network_id, Ordering::Relaxed); - self.network_domain.write().unwrap().clone_from(network_domain); + // self.network_domain.write().unwrap().clone_from(network_domain); + self.network_domain.store(Arc::new(network_domain.clone())); self.identity_id.store(identity_id); // *self._token.lock().unwrap() = token; @@ -389,6 +405,7 @@ impl Node { connecting_chan: Option>, hostname: String, udpsock_for_dns: Arc, + udp_sock_for_global_dns: Arc, server_ip: String, install_channel: String, ) -> Self { @@ -414,9 +431,11 @@ impl Node { route_table: RouteTable2::new(), - network_domain: RwLock::new(String::new()), + network_domain: ArcSwap::new(Arc::new(String::new())), udp_sock_for_dns: udpsock_for_dns, + udp_sock_for_global_dns: udp_sock_for_global_dns, + dns_matcher: Arc::new(DNSMatcher::new()), quic_endpoint: quic_init(), diff --git a/src/network/tun_linux.rs b/src/network/tun_linux.rs index 84d6e1b..7b5333b 100755 --- a/src/network/tun_linux.rs +++ b/src/network/tun_linux.rs @@ -4,16 +4,19 @@ use bytes::BytesMut; #[cfg(feature = "tun")] use bytes::{BytesMut}; +#[cfg(not(feature = "tun"))] +use etherparse::{IpSlice, LinkSlice, NetSlice, SlicedPacket, TransportSlice}; use etherparse::{Ethernet2Header}; use ipnet::Ipv4Net; use sdlan_sn_rs::config::SDLAN_DEFAULT_TTL; use sdlan_sn_rs::utils::{ - ip_to_string, is_ipv6_multicast, net_bit_len_to_mask, - SDLanError, + Mac, SDLanError, ip_to_string, is_ipv6_multicast, net_bit_len_to_mask }; use std::ffi::CStr; use std::ffi::{c_char, c_int}; use std::fs::{self, OpenOptions}; +#[cfg(not(feature = "tun"))] +use std::net::IpAddr; use std::net::Ipv4Addr; use std::os::unix::fs::{MetadataExt, PermissionsExt}; use std::path::Path; @@ -25,13 +28,13 @@ use std::io::{BufRead, BufReader, Read, Write}; use std::os::fd::AsRawFd; use std::process::Command; -use tracing::{debug, error, info}; +use tracing::{debug, error, info, warn}; #[cfg(feature = "tun")] use crate::caculate_crc; use crate::get_edge; #[cfg(not(feature = "tun"))] -use crate::network::{ARP_REPLY, ArpHdr, EthHdr}; +use crate::network::{ARP_REPLY, ArpHdr, EthHdr, parse_dns_payload}; use crate::network::{Node, send_packet_to_net}; #[cfg(not(feature = "tun"))] use crate::pb::SdlArpResponse; @@ -228,6 +231,8 @@ impl TunTapPacketHandler for Iface { } } + + #[cfg(feature="abc")] async fn handle_packet_from_device( &self, data: BytesMut, @@ -378,6 +383,141 @@ impl TunTapPacketHandler for Iface { Ok(()) } + + async fn handle_packet_from_device( + &self, + data: BytesMut, + // encrypt_key: &[u8], + ) -> std::io::Result<()> { + use etherparse::PacketHeaders; + + debug!("in tap mode2"); + let edge = get_edge(); + + let Ok((eth, layer3)) = Ethernet2Header::from_slice(&data) else { + error!("failed to parse packet"); + return Ok(()); + }; + + // if let Some(eth) = headers.link { + use etherparse::EtherType; + use bytes::Bytes; + + if eth.ether_type == EtherType::ARP { + use crate::network::{ARP_REQUEST, ArpHdr}; + + let arp = ArpHdr::from_slice(&data); + match arp.opcode { + ARP_REQUEST => { + let dest_ip = ((arp.dipaddr[0] as u32) << 16) + arp.dipaddr[1] as u32; + if dest_ip == DNS_IP { + error!("got dns ip"); + edge.device_config.dns_mac; + write_arp_to_device(edge, edge.device_config.dns_mac, DNS_IP); + return Ok(()); + } + + if edge.device_config.contains(&Ipv4Addr::from_bits(dest_ip)) { + let _ = edge.send_arp_request(dest_ip, dest_ip).await; + } else { + if let Some((_, real_ip)) = edge.route_table.lookup(dest_ip) { + let real_ip = u32::from_be_bytes(real_ip.octets()); + let _ = edge.send_arp_request(dest_ip, real_ip).await; + } + } + return Ok(()); + } + _other => { + // just do the following logic + } + } + } + let Ok(net_slice) = SlicedPacket::from_ip(layer3) else { + return Ok(()); + }; + + if let Some(ip) = net_slice.net{ + + match ip { + NetSlice::Ipv4(ipv4) => { + use crate::FiveTuple; + use etherparse::IpNumber; + if let Some(transport) = net_slice.transport { + match transport { + TransportSlice::Tcp(tcp) => { + let out_five_tuple = FiveTuple { + src_ip: IpAddr::V4(ipv4.header().source_addr()), + dst_ip: IpAddr::V4(ipv4.header().destination_addr()), + src_port: tcp.source_port(), + dst_port: tcp.destination_port(), + proto: IpNumber::TCP.0, + }; + edge.rule_cache.touch_packet(out_five_tuple); + } + TransportSlice::Udp(udp) => { + let out_five_tuple = FiveTuple { + src_ip: IpAddr::V4(ipv4.header().source_addr()), + dst_ip: IpAddr::V4(ipv4.header().destination_addr()), + src_port: udp.source_port(), + dst_port: udp.destination_port(), + proto: IpNumber::UDP.0, + }; + edge.rule_cache.touch_packet(out_five_tuple); + + if u32::from_be_bytes(ipv4.header().destination()) == DNS_IP { + // should send to dns + let source_ip = u32::from_be_bytes(ipv4.header().source()); + parse_dns_payload(edge, udp.payload(), layer3, source_ip, udp.source_port()).await; + // edge.udp_sock_for_dns.send_to() + return Ok(()) + } + } + _other => { + // ignore icmp and icmpv6 + } + } + } + } + NetSlice::Ipv6(_ipv6) => { + // not handling the ipv6 packet + // return Ok(()) + // just ignore + } + } + + } + + let target = eth.destination; + if is_ipv6_multicast(&target) { + return Ok(()); + } + + let size = data.len(); + + let Ok(encrypted) = edge.encryptor.load().encrypt(&data) else { + // let Ok(encrypted) = edge.encryptor.read().unwrap().encrypt(&data) else { + // let Ok(encrypted) = aes_encrypt(encrypt_key, &data) else { + error!("failed to encrypt packet request"); + return Ok(()); + }; + let data_bytes = Bytes::from(encrypted); + let data = SdlData { + is_p2p: true, + network_id: edge.network_id.load(Ordering::Relaxed), + ttl: SDLAN_DEFAULT_TTL as u32, + src_mac: Vec::from(edge.device_config.get_mac()), + dst_mac: Vec::from(target), + data: data_bytes, + identity_id: edge.identity_id.load(), + session_token: edge.session_token.get(), + }; + let msg = encode_to_udp_message(Some(data), PacketType::Data as u8).unwrap(); + + send_packet_to_net(edge, target, &msg, size as u64).await; + + Ok(()) + } + } #[cfg(feature = "tun")] @@ -704,13 +844,13 @@ fn check_has_resolvectl() -> bool { } } -fn add_dns_route(gw: &str) -> Result<()>{ +fn add_dns_route(dev_name: &str) -> Result<()>{ Command::new("route") .arg("add") .arg("-host") .arg("100.100.100.100") - .arg("gw") - .arg(gw) + .arg("dev") + .arg(dev_name) .output()?; Ok(()) @@ -741,13 +881,14 @@ fn set_dns( network_domain: &str, gw: &str ) -> Result<()> { + error!("network_domain = {}", network_domain); if iface.has_resolvectl { add_resolvectl(name, network_domain)?; } else { backup_resolv_conf()?; modify_resolv_conf(&vec!["100.100.100.100".to_owned()], network_domain, true)?; } - add_dns_route(gw)?; + add_dns_route(name)?; Ok(()) } @@ -998,14 +1139,18 @@ pub async fn arp_reply_arrived(edge: &Node, data: SdlArpResponse) { error!("invalid target_mac: {:?}, ip={}", data.target_mac, ip_to_string(&data.target_ip)); return; } - // TODO: construct the arp reply, and write to tun; let src_mac = data.target_mac.try_into().unwrap(); - let dst_mac = edge.device_config.get_mac(); - let dst_ip = edge.device_config.get_ip(); let src_ip = data.origin_ip; + write_arp_to_device(edge, src_mac, src_ip); +} + +pub fn write_arp_to_device(edge: &Node, src_mac: Mac, src_ip: u32) { + let dst_mac = edge.device_config.get_mac(); + let dst_ip = edge.device_config.get_ip(); + let hdr = ArpHdr{ ethhdr: EthHdr { dest: dst_mac, @@ -1027,7 +1172,5 @@ pub async fn arp_reply_arrived(edge: &Node, data: SdlArpResponse) { if let Err(_e) = edge.device.send(&data) { error!("failed to write arp response to device"); } -} -fn parse_dns_payload(edge: &Node, payload: &[u8]) { } \ No newline at end of file diff --git a/src/network/tuntap.rs b/src/network/tuntap.rs index f4e89cd..13de57c 100755 --- a/src/network/tuntap.rs +++ b/src/network/tuntap.rs @@ -9,12 +9,12 @@ use sdlan_sn_rs::{ utils::{Mac, Result, get_current_timestamp, ip_to_string}, }; -use tracing::debug; +use tracing::{debug, warn}; use tracing::error; use crate::{ - network::{RouteInfo, form_ethernet_packet, send_packet_to_net}, + network::{Node, RouteInfo, form_ethernet_packet, send_packet_to_net}, pb::{SdlData, encode_to_udp_message}, tcp::PacketType, utils::mac_to_string, @@ -24,6 +24,8 @@ 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 + 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<()>; @@ -136,4 +138,66 @@ pub async fn arp_arrived(ip: u32, mac: Mac) { waitlist.arp_arrived(ip, mac).await; } -*/ \ No newline at end of file +*/ + +pub fn get_dns_gateway(edge: &Node, payload: &[u8]) -> Option { + let dns_packet = match simple_dns::Packet::parse(payload) { + Err(e) => { + error!("failed to parse dns packet: {}", e); + return None; + } + 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]; + let domain = question.qname.to_string(); + + let self_domain = &edge.network_domain.load(); + if self_domain.is_empty() { + return None; + } + + if domain.ends_with(self_domain.as_str()) { + debug!("got dns request for domain {}, which ends with our network domain {}, should send to dns server", domain, self_domain); + return Some(domain); + } + } + return None; +} + +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()); + // should send to our socket + 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); + 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()); + 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 { + error!("failed to query for global dns: {}", e); + } + } + // edge.udp_sock_for_global_dns.send_to() + } + } + } + Err(e) => { + error!("failed to parse dns packet"); + } + } +} \ No newline at end of file diff --git a/src/tcp/quic.rs b/src/tcp/quic.rs index 8f87e8d..7e79e47 100644 --- a/src/tcp/quic.rs +++ b/src/tcp/quic.rs @@ -188,7 +188,7 @@ 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.read().unwrap().clone()); + edge.device.reload_config(edge, &edge.device_config, &edge.network_domain.load()); edge.set_authorized(true); diff --git a/src/utils/dns.rs b/src/utils/dns.rs new file mode 100644 index 0000000..1de6948 --- /dev/null +++ b/src/utils/dns.rs @@ -0,0 +1,47 @@ +use std::sync::{Arc, atomic::AtomicU16}; + +use dashmap::DashMap; +use sdlan_sn_rs::utils::get_current_timestamp; + +pub struct DNSCacheInfo { + pub src_ip: u32, + pub src_port: u16, + pub origin_transaction_id: u16, + pub added: u64, +} + +pub struct DNSMatcher { + current_transaction_id: AtomicU16, + // match transaction_id to (client ip, client port) + matcher: DashMap, +} + +impl DNSMatcher { + pub fn new() -> Self { + Self { + current_transaction_id: AtomicU16::new(0), + matcher: DashMap::new(), + } + } + + pub fn retain(&self) { + let now = get_current_timestamp(); + self.matcher.retain(|_, v| (now - v.added) < 10); + } + + pub fn generate_transaction_id(&self, client_ip: u32, client_port: u16, origin_transaction_id: u16) -> u16 { + let transaction_id = self.current_transaction_id.fetch_add(1, std::sync::atomic::Ordering::Relaxed); + self.matcher.insert(transaction_id, DNSCacheInfo{ + src_ip: client_ip, + src_port: client_port, + origin_transaction_id, + added: get_current_timestamp(), + }); + transaction_id + } + + pub fn get_client_info(&self, transaction_id: u16) -> Option<(u32, u16, u16)> { + let res = self.matcher.remove(&transaction_id)?; + Some((res.1.src_ip, res.1.src_port, res.1.origin_transaction_id)) + } +} \ No newline at end of file diff --git a/src/utils/mod.rs b/src/utils/mod.rs index aae3e29..ced2824 100755 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -3,6 +3,7 @@ mod acl_session; mod encrypter; mod system_action; mod file_configuration; +mod dns; use std::{fs::OpenOptions, io::Write, net::Ipv4Addr, path::Path}; @@ -10,6 +11,7 @@ pub use encrypter::*; pub use command::*; pub use acl_session::*; pub use system_action::*; +pub use dns::*; mod socks; use rand::Rng; @@ -30,6 +32,7 @@ pub struct CachedLoginInfo { pub audit: u32, pub network_id: u32, pub network_name: String, + pub network_domain: String, } // pub const CRC_HASH: crc::Crc = crc::Crc::::new(&crc::CRC_32_XFER);