diff --git a/Cargo.lock b/Cargo.lock index 4ad14fdcadfd..c05b121d2ff5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -105,6 +105,15 @@ dependencies = [ "syn", ] +[[package]] +name = "atomic-polyfill" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28" +dependencies = [ + "critical-section", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -377,6 +386,12 @@ dependencies = [ "libc", ] +[[package]] +name = "critical-section" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6548a0ad5d2549e111e1f6a11a6c2e2d00ce6a3dafe22948d67c2b443f775e52" + [[package]] name = "crossbeam-channel" version = "0.5.6" @@ -488,6 +503,35 @@ version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" +[[package]] +name = "defmt" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3a0ae7494d9bff013d7b89471f4c424356a71e9752e0c78abe7e6c608a16bb3" +dependencies = [ + "bitflags", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8500cbe4cca056412efce4215a63d0bc20492942aeee695f23b624a53e0a6854" +dependencies = [ + "defmt-parser", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "defmt-parser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0db23d29972d99baa3de2ee2ae3f104c10564a6d05a346eb3f4c4f2c0525a06e" + [[package]] name = "der" version = "0.6.1" @@ -852,12 +896,34 @@ dependencies = [ "tracing", ] +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "heapless" +version = "0.7.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743" +dependencies = [ + "atomic-polyfill", + "hash32", + "rustc_version", + "spin 0.9.5", + "stable_deref_trait", +] + [[package]] name = "heck" version = "0.4.1" @@ -1681,6 +1747,30 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.51" @@ -1875,6 +1965,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.36.8" @@ -2004,6 +2103,12 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" + [[package]] name = "sendfd" version = "0.4.3" @@ -2284,12 +2389,15 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "smoltcp" -version = "0.8.2" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee34c1e1bfc7e9206cc0fb8030a90129b4e319ab53856249bb27642cab914fb3" +checksum = "7e9786ac45091b96f946693e05bfa4d8ca93e2d3341237d97a380107a6b38dea" dependencies = [ "bitflags", "byteorder", + "cfg-if", + "defmt", + "heapless", "log", "managed", ] @@ -2347,6 +2455,12 @@ dependencies = [ "der", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "static_assertions" version = "1.1.0" diff --git a/crates/shadowsocks-service/Cargo.toml b/crates/shadowsocks-service/Cargo.toml index 6fd8b9478cc2..4c64a258aea5 100644 --- a/crates/shadowsocks-service/Cargo.toml +++ b/crates/shadowsocks-service/Cargo.toml @@ -116,7 +116,7 @@ regex = "1.4" tun = { version = "0.5.3", optional = true, features = ["async"] } etherparse = { version = "0.13", optional = true } -smoltcp = { version = "0.8", optional = true, default-features = false, features = ["std", "log", "medium-ip", "proto-ipv4", "proto-ipv6", "socket-icmp", "socket-udp", "socket-tcp"] } +smoltcp = { version = "0.9", optional = true, default-features = false, features = ["std", "log", "medium-ip", "proto-ipv4", "proto-ipv6", "socket-icmp", "socket-udp", "socket-tcp"] } serde = { version = "1.0", features = ["derive"] } json5 = "0.4" diff --git a/crates/shadowsocks-service/src/local/tun/ip_packet.rs b/crates/shadowsocks-service/src/local/tun/ip_packet.rs index 5a1f119cfdbc..3f9fabfd0a12 100644 --- a/crates/shadowsocks-service/src/local/tun/ip_packet.rs +++ b/crates/shadowsocks-service/src/local/tun/ip_packet.rs @@ -11,12 +11,11 @@ pub enum IpPacket> { } impl + Copy> IpPacket { - pub fn new_checked(packet: T) -> smoltcp::Result>> { + pub fn new_checked(packet: T) -> smoltcp::wire::Result>> { let buffer = packet.as_ref(); match IpVersion::of_packet(buffer)? { IpVersion::Ipv4 => Ok(Some(IpPacket::Ipv4(Ipv4Packet::new_checked(packet)?))), IpVersion::Ipv6 => Ok(Some(IpPacket::Ipv6(Ipv6Packet::new_checked(packet)?))), - _ => Ok(None), } } @@ -36,7 +35,7 @@ impl + Copy> IpPacket { pub fn protocol(&self) -> IpProtocol { match *self { - IpPacket::Ipv4(ref packet) => packet.protocol(), + IpPacket::Ipv4(ref packet) => packet.next_header(), IpPacket::Ipv6(ref packet) => packet.next_header(), } } diff --git a/crates/shadowsocks-service/src/local/tun/mod.rs b/crates/shadowsocks-service/src/local/tun/mod.rs index 3cbfb7bbffe1..a8d7b5fc2f9d 100644 --- a/crates/shadowsocks-service/src/local/tun/mod.rs +++ b/crates/shadowsocks-service/src/local/tun/mod.rs @@ -206,7 +206,7 @@ impl Tun { } } - async fn handle_tun_frame(&mut self, frame: &[u8]) -> smoltcp::Result<()> { + async fn handle_tun_frame(&mut self, frame: &[u8]) -> smoltcp::wire::Result<()> { let packet = match IpPacket::new_checked(frame)? { Some(packet) => packet, None => { diff --git a/crates/shadowsocks-service/src/local/tun/tcp.rs b/crates/shadowsocks-service/src/local/tun/tcp.rs index 03c5bdc17caa..77366f9a515f 100644 --- a/crates/shadowsocks-service/src/local/tun/tcp.rs +++ b/crates/shadowsocks-service/src/local/tun/tcp.rs @@ -1,5 +1,5 @@ use std::{ - collections::{BTreeMap, HashMap}, + collections::HashMap, io::{self, ErrorKind}, mem, net::{IpAddr, SocketAddr}, @@ -16,9 +16,9 @@ use std::{ use log::{error, trace}; use shadowsocks::{net::TcpSocketOpts, relay::socks5::Address}; use smoltcp::{ - iface::{Interface, InterfaceBuilder, Routes, SocketHandle}, + iface::{Config as InterfaceConfig, Interface, SocketHandle, SocketSet}, phy::{DeviceCapabilities, Medium}, - socket::{TcpSocket, TcpSocketBuffer, TcpState}, + socket::{tcp::Socket as TcpSocket, tcp::SocketBuffer as TcpSocketBuffer, tcp::State as TcpState}, storage::RingBuffer, time::{Duration as SmolDuration, Instant as SmolInstant}, wire::{IpAddress, IpCidr, Ipv4Address, Ipv6Address, TcpPacket}, @@ -68,7 +68,8 @@ impl ManagerNotify { } struct TcpSocketManager { - iface: Interface<'static, VirtTunDevice>, + device: VirtTunDevice, + iface: Interface, sockets: HashMap, socket_creation_rx: mpsc::UnboundedReceiver, } @@ -228,28 +229,32 @@ impl TcpTun { capabilities.medium = Medium::Ip; capabilities.max_transmission_unit = mtu as usize; - let (virt, iface_rx, iface_tx) = VirtTunDevice::new(capabilities); - - let iface_builder = InterfaceBuilder::new(virt, vec![]); - let iface_ipaddrs = [ - IpCidr::new(IpAddress::v4(0, 0, 0, 1), 0), - IpCidr::new(IpAddress::v6(0, 0, 0, 0, 0, 0, 0, 1), 0), - ]; - let mut iface_routes = Routes::new(BTreeMap::new()); - iface_routes + let (mut device, iface_rx, iface_tx) = VirtTunDevice::new(capabilities); + + let mut iface_config = InterfaceConfig::default(); + iface_config.random_seed = rand::random(); + let mut iface = Interface::new(iface_config, &mut device); + iface.update_ip_addrs(|ip_addrs| { + ip_addrs + .push(IpCidr::new(IpAddress::v4(0, 0, 0, 1), 0)) + .expect("iface IPv4"); + ip_addrs + .push(IpCidr::new(IpAddress::v6(0, 0, 0, 0, 0, 0, 0, 1), 0)) + .expect("iface IPv6"); + }); + iface + .routes_mut() .add_default_ipv4_route(Ipv4Address::new(0, 0, 0, 1)) - .expect("IPv4 route"); - iface_routes + .expect("IPv4 default route"); + iface + .routes_mut() .add_default_ipv6_route(Ipv6Address::new(0, 0, 0, 0, 0, 0, 0, 1)) - .expect("IPv6 route"); - let iface = iface_builder - .any_ip(true) - .ip_addrs(iface_ipaddrs) - .routes(iface_routes) - .finalize(); + .expect("IPv6 default route"); + iface.set_any_ip(true); let (manager_socket_creation_tx, manager_socket_creation_rx) = mpsc::unbounded_channel(); let mut manager = TcpSocketManager { + device, iface, sockets: HashMap::new(), socket_creation_rx: manager_socket_creation_rx, @@ -262,26 +267,23 @@ impl TcpTun { thread::spawn(move || { let TcpSocketManager { + ref mut device, ref mut iface, ref mut sockets, ref mut socket_creation_rx, .. } = manager; + let mut socket_set = SocketSet::new(vec![]); + while manager_running.load(Ordering::Relaxed) { while let Ok(TcpSocketCreation { control, socket }) = socket_creation_rx.try_recv() { - let handle = iface.add_socket(socket); + let handle = socket_set.add(socket); sockets.insert(handle, control); } let before_poll = SmolInstant::now(); - let updated_sockets = match iface.poll(before_poll) { - Ok(u) => u, - Err(err) => { - error!("VirtDevice::poll error: {}", err); - false - } - }; + let updated_sockets = iface.poll(before_poll, device, &mut socket_set); if updated_sockets { trace!("VirtDevice::poll costed {}", SmolInstant::now() - before_poll); @@ -292,7 +294,7 @@ impl TcpTun { for (socket_handle, control) in sockets.iter() { let socket_handle = *socket_handle; - let socket = iface.get_socket::(socket_handle); + let socket = socket_set.get_mut::(socket_handle); let mut control = control.lock(); #[inline] @@ -333,7 +335,7 @@ impl TcpTun { has_received = true; } Err(err) => { - error!("socket recv error: {}", err); + error!("socket recv error: {:?}", err); sockets_to_remove.push(socket_handle); close_socket_control(&mut control); break; @@ -360,7 +362,7 @@ impl TcpTun { has_sent = true; } Err(err) => { - error!("socket send error: {}", err); + error!("socket send error: {:?}", err); sockets_to_remove.push(socket_handle); close_socket_control(&mut control); break; @@ -377,10 +379,12 @@ impl TcpTun { for socket_handle in sockets_to_remove { sockets.remove(&socket_handle); - iface.remove_socket(socket_handle); + socket_set.remove(socket_handle); } - let next_duration = iface.poll_delay(before_poll).unwrap_or(SmolDuration::from_millis(5)); + let next_duration = iface + .poll_delay(before_poll, &socket_set) + .unwrap_or(SmolDuration::from_millis(5)); if next_duration != SmolDuration::ZERO { thread::park_timeout(Duration::from(next_duration)); } @@ -428,7 +432,7 @@ impl TcpTun { // socket.set_ack_delay(None); if let Err(err) = socket.listen(dst_addr) { - return Err(io::Error::new(ErrorKind::Other, err)); + return Err(io::Error::new(ErrorKind::Other, format!("listen error: {:?}", err))); } trace!("created TCP connection for {} <-> {}", src_addr, dst_addr); diff --git a/crates/shadowsocks-service/src/local/tun/virt_device.rs b/crates/shadowsocks-service/src/local/tun/virt_device.rs index d3246deb1369..e9b89131960e 100644 --- a/crates/shadowsocks-service/src/local/tun/virt_device.rs +++ b/crates/shadowsocks-service/src/local/tun/virt_device.rs @@ -1,5 +1,7 @@ //! Virtual Device for receiving packets from tun +use std::marker::PhantomData; + use smoltcp::{ phy::{self, Device, DeviceCapabilities}, time::Instant, @@ -31,20 +33,23 @@ impl VirtTunDevice { } } -impl<'a> Device<'a> for VirtTunDevice { - type RxToken = VirtRxToken; - type TxToken = VirtTxToken<'a>; +impl Device for VirtTunDevice { + type RxToken<'a> = VirtRxToken<'a>; + type TxToken<'a> = VirtTxToken<'a>; - fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { + fn receive<'a>(&'a mut self, _timestamp: Instant) -> Option<(Self::RxToken<'a>, Self::TxToken<'a>)> { if let Ok(buffer) = self.in_buf.try_recv() { - let rx = Self::RxToken { buffer }; + let rx = Self::RxToken { + buffer, + phantom_device: PhantomData::default(), + }; let tx = VirtTxToken(self); return Some((rx, tx)); } None } - fn transmit(&'a mut self) -> Option { + fn transmit<'a>(&'a mut self, _timestamp: Instant) -> Option> { return Some(VirtTxToken(self)); } @@ -53,14 +58,15 @@ impl<'a> Device<'a> for VirtTunDevice { } } -pub struct VirtRxToken { +pub struct VirtRxToken<'a> { buffer: Vec, + phantom_device: PhantomData<&'a VirtTunDevice>, } -impl phy::RxToken for VirtRxToken { - fn consume(mut self, _timestamp: Instant, f: F) -> smoltcp::Result +impl phy::RxToken for VirtRxToken<'_> { + fn consume(mut self, f: F) -> R where - F: FnOnce(&mut [u8]) -> smoltcp::Result, + F: FnOnce(&mut [u8]) -> R, { f(&mut self.buffer[..]) } @@ -69,9 +75,9 @@ impl phy::RxToken for VirtRxToken { pub struct VirtTxToken<'a>(&'a mut VirtTunDevice); impl<'a> phy::TxToken for VirtTxToken<'a> { - fn consume(self, _timestamp: Instant, len: usize, f: F) -> smoltcp::Result + fn consume(self, len: usize, f: F) -> R where - F: FnOnce(&mut [u8]) -> smoltcp::Result, + F: FnOnce(&mut [u8]) -> R, { let mut buffer = vec![0u8; len]; let result = f(&mut buffer);