From c9f35158b250c60363ddb670bc5e87c10e746af1 Mon Sep 17 00:00:00 2001 From: Samuka007 Date: Tue, 22 Apr 2025 13:43:47 +0800 Subject: [PATCH] can use tap to receive packages --- Cargo.lock | 202 ++++++++++++++++++++++++++++++++++ Cargo.toml | 2 + src/driver/irq.rs | 12 +- src/driver/mod.rs | 20 ++-- src/driver/tap.rs | 112 ++++++++++--------- src/interface/tap.rs | 6 +- src/main.rs | 34 ++++-- src/socket/inet/common/mod.rs | 2 - 8 files changed, 306 insertions(+), 84 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d6ca64a..c015b16 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,71 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "allocator-api2" version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +dependencies = [ + "anstyle", + "once_cell", + "windows-sys", +] + [[package]] name = "anyhow" version = "1.0.98" @@ -25,6 +84,7 @@ name = "berkeley-socket" version = "0.1.0" dependencies = [ "bitflags 2.9.0", + "env_logger", "hashbrown", "lazy_static", "libc", @@ -33,6 +93,7 @@ dependencies = [ "netsock", "num-derive", "num-traits", + "scopeguard", "smoltcp", "spin", ] @@ -67,6 +128,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + [[package]] name = "defmt" version = "0.3.100" @@ -108,6 +175,29 @@ dependencies = [ "thiserror 2.0.12", ] +[[package]] +name = "env_filter" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -150,6 +240,36 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "jiff" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a064218214dc6a10fbae5ec5fa888d80c45d611aba169222fc272072bf7aef6" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "jiff-static" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "199b7932d97e325aff3a7030e141eafe7f2c6268e1d1b24859b753a627f45254" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -190,6 +310,12 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d" +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + [[package]] name = "netlink-packet-core" version = "0.7.0" @@ -277,12 +403,33 @@ dependencies = [ "autocfg", ] +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + [[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "portable-atomic" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + [[package]] name = "proc-macro-error-attr2" version = "2.0.0" @@ -323,12 +470,61 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "smallvec" version = "1.15.0" @@ -422,6 +618,12 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "windows-sys" version = "0.59.0" diff --git a/Cargo.toml b/Cargo.toml index f5601f8..63df627 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,3 +26,5 @@ log = "*" netsock = "0.3.0" libc = "0.2.172" lazy_static = "1.5.0" +scopeguard = "1.2.0" +env_logger = "0.11.8" diff --git a/src/driver/irq.rs b/src/driver/irq.rs index 837a01f..9b1e6d3 100644 --- a/src/driver/irq.rs +++ b/src/driver/irq.rs @@ -46,6 +46,7 @@ pub fn start_network_polling_thread() -> io::Result> { // Process events for event in events.iter().take(num_events as usize) { + log::trace!("epoll_wait returned {} events", num_events); let fd = event.u64 as RawFd; if let Some(&device_id) = fd_to_device_id.get(&fd) { @@ -56,11 +57,11 @@ pub fn start_network_polling_thread() -> io::Result> { } } - // Also poll all devices periodically regardless of events - // This ensures timers and other internal state are updated - for device in NET_DEVICES.read().values() { - device.poll(); - } + // // Also poll all devices periodically regardless of events + // // This ensures timers and other internal state are updated + // for device in NET_DEVICES.read().values() { + // device.poll(); + // } // Small sleep to prevent CPU hogging thread::sleep(Duration::from_millis(1)); @@ -90,6 +91,7 @@ fn update_watched_devices(epoll_fd: RawFd, fd_to_device_id: &mut HashMap ifreq { let mut ifreq = ifreq { - ifr_name: [0; libc::IF_NAMESIZE], - ifr_data: 0, + ifr_name: [0; libc::IFNAMSIZ], + ifr_ifru: unsafe { mem::zeroed() }, }; for (i, byte) in name.as_bytes().iter().enumerate() { ifreq.ifr_name[i] = *byte as libc::c_char @@ -24,15 +19,14 @@ fn ifreq_for(name: &str) -> ifreq { fn ifreq_ioctl( lower: libc::c_int, - ifreq: &mut ifreq, cmd: libc::c_ulong, -) -> io::Result { + ifreq: &mut ifreq, +) -> io::Result { unsafe { let res = libc::ioctl(lower, cmd as _, ifreq as *mut ifreq); if res == -1 { return Err(io::Error::last_os_error()); } + Ok(res) } - - Ok(ifreq.ifr_data) } diff --git a/src/driver/tap.rs b/src/driver/tap.rs index 8f23909..58c8ba9 100644 --- a/src/driver/tap.rs +++ b/src/driver/tap.rs @@ -1,4 +1,5 @@ use super::*; +use scopeguard::defer; use smoltcp::{phy::Medium, wire::EthernetFrame}; use std::io; use std::os::unix::io::{AsRawFd, RawFd}; @@ -7,6 +8,7 @@ use std::os::unix::io::{AsRawFd, RawFd}; pub struct TapDesc { lower: libc::c_int, mtu: usize, + mac: smoltcp::wire::EthernetAddress, } impl AsRawFd for TapDesc { @@ -29,27 +31,23 @@ impl TapDesc { }; let mut ifreq = ifreq_for(name); - Self::attach_interface_ifreq(lower, medium, &mut ifreq)?; + Self::attach_interface_ifreq(lower, &mut ifreq)?; + log::trace!("Successfully attach interface: {}", name); let mtu = Self::mtu_ifreq(medium, &mut ifreq)?; + log::trace!("Successfully get MTU: {}", mtu); + let mac = Self::mac_ifreq(&mut ifreq)?; + log::trace!("Successfully get MAC: {}", mac); - Ok(TapDesc { lower, mtu }) + Ok(TapDesc { lower, mtu, mac }) } - pub fn from_fd(fd: RawFd, mtu: usize) -> io::Result { - Ok(TapDesc { lower: fd, mtu }) - } + // pub fn from_fd(fd: RawFd, mtu: usize) -> io::Result { + // Ok(TapDesc { lower: fd, mtu }) + // } - fn attach_interface_ifreq( - lower: libc::c_int, - medium: Medium, - ifr: &mut ifreq, - ) -> io::Result<()> { - let mode = match medium { - Medium::Ip => libc::IFF_TUN, - Medium::Ethernet => libc::IFF_TAP, - }; - ifr.ifr_data = mode | libc::IFF_NO_PI; - ifreq_ioctl(lower, ifr, libc::TUNSETIFF).map(|_| ()) + fn attach_interface_ifreq(lower: libc::c_int, ifr: &mut ifreq) -> io::Result<()> { + ifr.ifr_ifru.ifru_flags = (libc::IFF_TAP | libc::IFF_NO_PI) as libc::c_short; + ifreq_ioctl(lower, libc::TUNSETIFF, ifr).map(|_| ()) } fn mtu_ifreq(medium: Medium, ifr: &mut ifreq) -> io::Result { @@ -60,15 +58,13 @@ impl TapDesc { } lower }; - - let ip_mtu = ifreq_ioctl(lower, ifr, libc::SIOCGIFMTU).map(|mtu| mtu as usize); - - unsafe { + defer!(unsafe { libc::close(lower); - } + }); - // Propagate error after close, to ensure we always close. - let ip_mtu = ip_mtu?; + let _ = ifreq_ioctl(lower, libc::SIOCGIFMTU, ifr)?; + + let ip_mtu = unsafe { ifr.ifr_ifru.ifru_mtu } as usize; // SIOCGIFMTU returns the IP MTU (typically 1500 bytes.) // smoltcp counts the entire Ethernet packet in the MTU, so add the Ethernet header size to it. @@ -81,6 +77,31 @@ impl TapDesc { Ok(mtu) } + fn mac_ifreq(ifr: &mut ifreq) -> io::Result { + let lower = unsafe { + let lower = libc::socket(libc::AF_INET, libc::SOCK_DGRAM, libc::IPPROTO_IP); + if lower == -1 { + return Err(io::Error::last_os_error()); + } + lower + }; + defer!(unsafe { + libc::close(lower); + }); + + let mac = smoltcp::wire::EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]); + + unsafe { + ifr.ifr_ifru.ifru_hwaddr.sa_family = libc::ARPHRD_ETHER as u16; + ifr.ifr_ifru.ifru_hwaddr.sa_data[..6] + .copy_from_slice(&[0x02, 0x00, 0x00, 0x00, 0x00, 0x01]); + } + + let _ = ifreq_ioctl(lower, libc::SIOCSIFHWADDR, ifr)?; + + Ok(mac) + } + pub fn interface_mtu(&self) -> io::Result { Ok(self.mtu) } @@ -135,7 +156,6 @@ pub struct TapDevice { lower: Rc>, mtu: usize, medium: Medium, - mac: smoltcp::wire::EthernetAddress, } impl AsRawFd for TapDevice { @@ -153,46 +173,28 @@ impl TapDevice { pub fn new(name: &str, medium: Medium) -> io::Result { let lower = crate::driver::TapDesc::new(name, medium)?; let mtu = lower.interface_mtu()?; - let mac = smoltcp::wire::EthernetAddress::from_bytes(&[ - 0x02, - 0x00, - 0x00, - std::random::random::(), - std::random::random::(), - std::random::random::(), - ]); Ok(TapDevice { lower: Rc::new(RefCell::new(lower)), mtu, medium, - mac, }) } - /// Attaches to a TUN/TAP interface specified by file descriptor `fd`. - /// - /// On platforms like Android, a file descriptor to a tun interface is exposed. - /// On these platforms, a TunTapInterface cannot be instantiated with a name. - pub fn from_fd(fd: RawFd, medium: Medium, mtu: usize) -> io::Result { - let lower = crate::driver::TapDesc::from_fd(fd, mtu)?; - let mac = smoltcp::wire::EthernetAddress::from_bytes(&[ - 0x02, - 0x00, - 0x00, - std::random::random::(), - std::random::random::(), - std::random::random::(), - ]); - Ok(TapDevice { - lower: Rc::new(RefCell::new(lower)), - mtu, - medium, - mac, - }) - } + // /// Attaches to a TUN/TAP interface specified by file descriptor `fd`. + // /// + // /// On platforms like Android, a file descriptor to a tun interface is exposed. + // /// On these platforms, a TunTapInterface cannot be instantiated with a name. + // pub fn from_fd(fd: RawFd, medium: Medium, mtu: usize) -> io::Result { + // let lower = crate::driver::TapDesc::from_fd(fd, mtu)?; + // Ok(TapDevice { + // lower: Rc::new(RefCell::new(lower)), + // mtu, + // medium, + // }) + // } pub fn mac(&self) -> smoltcp::wire::EthernetAddress { - self.mac + self.lower.borrow().mac } } diff --git a/src/interface/tap.rs b/src/interface/tap.rs index c34a5ae..b57ac9d 100644 --- a/src/interface/tap.rs +++ b/src/interface/tap.rs @@ -1,4 +1,4 @@ -use std::{ops::DerefMut, sync::Arc, time::Instant}; +use std::{ops::DerefMut, os::fd::AsRawFd, sync::Arc, time::Instant}; use smoltcp::{ iface::{Config, Interface}, @@ -59,4 +59,8 @@ impl Iface for TapIface { let reference = guard.deref_mut(); self.common.poll(reference); } + + fn raw_fd(&self) -> Option { + Some(self.inner.lock().as_raw_fd()) + } } diff --git a/src/main.rs b/src/main.rs index 46cace8..b196eb8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,26 +1,44 @@ -use std::sync::Arc; +use std::{net::Ipv4Addr, sync::Arc}; use berkeley_socket::{ - driver::{irq::start_network_polling_thread, tap::TapDevice}, interface::tap::TapIface, posix::SOCK, socket::{endpoint::Endpoint, inet::{common::NET_DEVICES, syscall::Inet}, Family} + driver::{irq::start_network_polling_thread, tap::TapDevice}, interface::{tap::TapIface, Iface}, posix::SOCK, socket::{endpoint::Endpoint, inet::{common::NET_DEVICES, syscall::Inet}, Family} }; -use smoltcp::wire::{IpAddress, IpEndpoint}; +use smoltcp::wire::{IpAddress, IpEndpoint, Ipv4Cidr, IpCidr}; use spin::Mutex; fn main() { + env_logger::init(); let device = TapDevice::new("tap0", smoltcp::phy::Medium::Ethernet).unwrap(); - let iface = Arc::new(TapIface::new(Arc::new(Mutex::new(device)))); + let iface_inner = TapIface::new(Arc::new(Mutex::new(device))); + + let ip_cidr = IpCidr::Ipv4(Ipv4Cidr::new( + Ipv4Addr::new(192, 168, 213, 2), + 24 + )); + + let ip_cidr = vec![ip_cidr]; + + iface_inner.update_ip_addrs(&ip_cidr).unwrap(); + + let iface = Arc::new(iface_inner); + NET_DEVICES.write().insert(0, iface); + scopeguard::defer!({ + NET_DEVICES.write().clear(); + }); let _ = start_network_polling_thread(); - // TODO: add socket tests let socket = Inet::socket(SOCK::Datagram, 0).unwrap(); socket.bind(Endpoint::Ip( IpEndpoint::new( - IpAddress::v4(192, 168, 199, 1), + IpAddress::v4(192, 168, 213, 2), 1234, ) )).unwrap(); let mut buffer = [0u8; 1024]; - socket.read(&mut buffer).unwrap(); - socket.write(&buffer).unwrap(); + + loop { + let len = socket.read(&mut buffer).unwrap(); + log::info!("Received {} bytes: {}", len, String::from_utf8_lossy(&buffer[..len])); + } } diff --git a/src/socket/inet/common/mod.rs b/src/socket/inet/common/mod.rs index dd77a40..fa4ff6b 100644 --- a/src/socket/inet/common/mod.rs +++ b/src/socket/inet/common/mod.rs @@ -21,8 +21,6 @@ pub enum Types { } lazy_static::lazy_static! { - /// # 所有网络接口的列表 - /// 这个列表在中断上下文会使用到,因此需要irqsave pub static ref NET_DEVICES: RwLock>> = RwLock::new(BTreeMap::new()); }