diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 66f055c..1b3e65a 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -62,6 +62,7 @@ dependencies = [ "buddy_system_allocator 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "isomorphic_drivers 0.1.0 (git+https://github.com/rcore-os/isomorphic_drivers)", "smoltcp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "treebitmap 0.3.1 (git+https://github.com/jiegec/treebitmap)", ] [[package]] @@ -80,6 +81,11 @@ name = "spin" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "treebitmap" +version = "0.3.1" +source = "git+https://github.com/jiegec/treebitmap#a89d725c1308719e327993dc5c5c0357c43dccf1" + [[package]] name = "volatile" version = "0.2.6" @@ -96,4 +102,5 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum managed 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fdcec5e97041c7f0f1c5b7d93f12e57293c831c646f4cc7a5db59460c7ea8de6" "checksum smoltcp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fef582369edb298c6c41319a544ca9c4e83622f226055ccfcb35974fbb55ed34" "checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" +"checksum treebitmap 0.3.1 (git+https://github.com/jiegec/treebitmap)" = "" "checksum volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6af0edf5b4faacc31fc51159244d78d65ec580f021afcef7bd53c04aeabc7f29" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 5c55341..aa3a560 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -7,4 +7,5 @@ edition = "2018" [dependencies] buddy_system_allocator = "0.1" isomorphic_drivers = { git = "https://github.com/rcore-os/isomorphic_drivers", default-features = false, features = ["log"]} -smoltcp = { version = "0.5.0", default-features = false, features = ["alloc", "log", "proto-ipv4", "socket-tcp", "socket-raw"] } \ No newline at end of file +smoltcp = { version = "0.5.0", default-features = false, features = ["alloc", "log", "proto-ipv4", "socket-tcp", "socket-raw"] } +treebitmap = { git = "https://github.com/jiegec/treebitmap" , features = ["alloc"] } \ No newline at end of file diff --git a/rust/src/bin/raw_socket.rs b/rust/src/bin/raw_socket.rs index fdb7350..0c903c7 100644 --- a/rust/src/bin/raw_socket.rs +++ b/rust/src/bin/raw_socket.rs @@ -1,12 +1,18 @@ +#![feature(alloc)] #![no_std] #![no_main] #[macro_use] extern crate rcore_user; +extern crate alloc; +extern crate treebitmap; + +use alloc::format; use core::default::Default; use core::mem::size_of; use rcore_user::syscall::{sys_ioctl, sys_read, sys_sendto, sys_setsockopt, sys_socket}; +use treebitmap::*; #[repr(C)] #[derive(Default)] @@ -46,16 +52,40 @@ struct ArpReq { arp_dev: [u8; 16], } +pub fn get_routing_table() -> IpLookupTable { + let mut table = IpLookupTable::new(); + // iface 0 10.0.0.0/24 00:16:31:ff:a4:9f enp0s4f0 + table.insert( + Ipv4Addr::new(10, 0, 0, 0), + 24, + (0, [0x00, 0x16, 0x31, 0xff, 0xa4, 0x9f], "enp0s4f0\0"), + ); + // iface 1 10.0.1.0/24 54:51:9f:71:c0:01 enp0s5f0 + table.insert( + Ipv4Addr::new(10, 0, 1, 0), + 24, + (1, [0x54, 0x51, 0x9f, 0x71, 0xc0, 0x01], "enp0s5f0\0"), + ); + + table +} + // IMPORTANT: Must define main() like this #[no_mangle] pub unsafe fn main() { println!("Raw socket test"); + // raw socket, icmp let capture_fd = sys_socket(2, 3, 1); // inet socket, udp let arp_fd = sys_socket(2, 2, 0); // packet socket, raw - let packet = sys_socket(17, 3, 0); + let packet_fd = sys_socket(17, 3, 0); + // netlink socket, raw + let netlink_fd = sys_socket(16, 3, 0); + + let table = get_routing_table(); + let mut buffer = [0u8; 2048]; // set header included let included = 1u32; @@ -78,7 +108,6 @@ pub unsafe fn main() { let mut arp: ArpReq = Default::default(); // inet arp.arp_pa.sin_family = 2; - arp.arp_dev[0..9].copy_from_slice(&[b'e', b'n', b'p', b'0', b's', b'4', b'f', b'0', 0]); loop { let len = sys_read( capture_fd as usize, @@ -86,39 +115,88 @@ pub unsafe fn main() { buffer.len(), ) as usize; println!("Got packet of len {}", len); - if ETHER_HEADER_LEN + len > 20 && buffer[ETHER_HEADER_LEN + 0] == 0x45 { + // check ethertype and ip version ihl + if ETHER_HEADER_LEN + len > 20 + && buffer[12] == 0x08 + && buffer[13] == 0x00 + && buffer[ETHER_HEADER_LEN + 0] == 0x45 + { // ipv4 let ttl = buffer[ETHER_HEADER_LEN + 8]; if ttl > 1 { - println!("ttl {}", ttl); - let dst_ip = (buffer[ETHER_HEADER_LEN + 19] as u32) << 24 - | (buffer[ETHER_HEADER_LEN + 18] as u32) << 16 - | (buffer[ETHER_HEADER_LEN + 17] as u32) << 8 - | (buffer[ETHER_HEADER_LEN + 16] as u32); - println!("dst_ip {:#X}", dst_ip); - arp.arp_pa.sin_addr = dst_ip; - // SIOCGARP - sys_ioctl(arp_fd as usize, 0x8954, &arp as *const ArpReq as usize); - println!("dst_mac {:X?}", &arp.arp_ha.sha_data[0..6]); - - // fill src and dst mac - // todo: get mac from if instead of hard coding - buffer[0..6].copy_from_slice(&[0, 0x16, 0x31, 0xFF, 0xA4, 0x9F]); - buffer[6..12].copy_from_slice(&arp.arp_ha.sha_data[0..6]); - buffer[ETHER_HEADER_LEN + 8] = ttl - 1; - let checksum = (buffer[ETHER_HEADER_LEN + 10] as u16) << 8 - | (buffer[ETHER_HEADER_LEN + 11] as u16); - buffer[ETHER_HEADER_LEN + 10] = ((checksum + 0x0100) >> 8) as u8; - buffer[ETHER_HEADER_LEN + 11] = (checksum + 0x0100) as u8; - addr.sll_ifindex = 0; - sys_sendto( - packet as usize, - buffer.as_ptr(), - len as usize + ETHER_HEADER_LEN, - 0, - &addr as *const SockAddrLl as usize, - size_of::(), + if buffer[ETHER_HEADER_LEN + 19] == 2 { + // to myself + println!("packet to myself"); + continue; + } + let lookup_ip = Ipv4Addr::new( + buffer[ETHER_HEADER_LEN + 16], + buffer[ETHER_HEADER_LEN + 17], + buffer[ETHER_HEADER_LEN + 18], + buffer[ETHER_HEADER_LEN + 19], ); + let route_match = table.longest_match(lookup_ip); + match route_match { + Some((_, _, (out_if, mac, name))) => { + let dst_ip = (buffer[ETHER_HEADER_LEN + 19] as u32) << 24 + | (buffer[ETHER_HEADER_LEN + 18] as u32) << 16 + | (buffer[ETHER_HEADER_LEN + 17] as u32) << 8 + | (buffer[ETHER_HEADER_LEN + 16] as u32); + arp.arp_pa.sin_addr = dst_ip; + arp.arp_dev[0..9].copy_from_slice(name.as_bytes()); + // SIOCGARP + if sys_ioctl(arp_fd as usize, 0x8954, &arp as *const ArpReq as usize) < 0 { + println!("dst ip not in arp table, skipping"); + continue; + } + + let message = format!("from {}.{}.{}.{} {:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X} to {}.{}.{}.{} {:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X} dev {}:{} with ttl {}", buffer[ETHER_HEADER_LEN + 12], + buffer[ETHER_HEADER_LEN+ 13], + buffer[ETHER_HEADER_LEN+ 14], + buffer[ETHER_HEADER_LEN+ 15], + mac[0], + mac[1], + mac[2], + mac[3], + mac[4], + mac[5], + buffer[ETHER_HEADER_LEN+ 16], + buffer[ETHER_HEADER_LEN+ 17], + buffer[ETHER_HEADER_LEN+ 18], + buffer[ETHER_HEADER_LEN+ 19], + arp.arp_ha.sha_data[0], + arp.arp_ha.sha_data[1], + arp.arp_ha.sha_data[2], + arp.arp_ha.sha_data[3], + arp.arp_ha.sha_data[4], + arp.arp_ha.sha_data[5], + out_if, + name, + ttl, + ); + println!("{}", message); + + // fill dst and src mac + // todo: get mac from if instead of hard coding + buffer[0..6].copy_from_slice(&arp.arp_ha.sha_data[0..6]); + buffer[6..12].copy_from_slice(mac); + buffer[ETHER_HEADER_LEN + 8] = ttl - 1; + let checksum = (buffer[ETHER_HEADER_LEN + 10] as u16) << 8 + | (buffer[ETHER_HEADER_LEN + 11] as u16); + buffer[ETHER_HEADER_LEN + 10] = ((checksum + 0x0100) >> 8) as u8; + buffer[ETHER_HEADER_LEN + 11] = (checksum + 0x0100) as u8; + addr.sll_ifindex = *out_if; + sys_sendto( + packet_fd as usize, + buffer.as_ptr(), + len as usize + ETHER_HEADER_LEN, + 0, + &addr as *const SockAddrLl as usize, + size_of::(), + ); + } + None => continue, + } } } } diff --git a/rust/src/io.rs b/rust/src/io.rs index 370101b..21bd6f3 100644 --- a/rust/src/io.rs +++ b/rust/src/io.rs @@ -194,8 +194,8 @@ impl fmt::Write for StdOut { pub const O_RDONLY: usize = 0; // open for reading only pub const O_WRONLY: usize = 1; // open for writing only pub const O_RDWR: usize = 2; // open for reading and writing -// then or in any of these: + // then or in any of these: pub const O_CREAT: usize = 0x00000004; // create file if it does not exist pub const O_EXCL: usize = 0x00000008; // error if O_CREAT and the file exists pub const O_TRUNC: usize = 0x00000010; // truncate file upon open -pub const O_APPEND: usize = 0x00000020; // append on each write \ No newline at end of file +pub const O_APPEND: usize = 0x00000020; // append on each write diff --git a/rust/src/lang_items.rs b/rust/src/lang_items.rs index 878a046..1900d18 100644 --- a/rust/src/lang_items.rs +++ b/rust/src/lang_items.rs @@ -1,9 +1,9 @@ use crate::syscall::sys_exit; use crate::ALLOCATOR; +use super::syscall::*; use core::alloc::Layout; use core::panic::PanicInfo; -use super::syscall::*; #[linkage = "weak"] #[no_mangle] @@ -14,7 +14,9 @@ fn main() { fn init_heap() { const HEAP_SIZE: usize = 0x1000; static mut HEAP: [u8; HEAP_SIZE] = [0; HEAP_SIZE]; - unsafe { ALLOCATOR.lock().init(HEAP.as_ptr() as usize, HEAP_SIZE); } + unsafe { + ALLOCATOR.lock().init(HEAP.as_ptr() as usize, HEAP_SIZE); + } } /// MIPS use __start for entry point instead of _start diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 1b22e9a..e345aba 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -10,10 +10,10 @@ extern crate alloc; #[macro_use] pub mod io; -pub mod syscall; pub mod lang_items; +pub mod syscall; use buddy_system_allocator::LockedHeap; #[global_allocator] -static ALLOCATOR: LockedHeap = LockedHeap::empty(); \ No newline at end of file +static ALLOCATOR: LockedHeap = LockedHeap::empty(); diff --git a/rust/src/syscall.rs b/rust/src/syscall.rs index 9e012b7..d743b69 100644 --- a/rust/src/syscall.rs +++ b/rust/src/syscall.rs @@ -2,32 +2,40 @@ use crate::ALLOCATOR; use alloc::string::String; #[inline(always)] -fn sys_call(syscall_id: SyscallId, arg0: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) -> i32 { +fn sys_call( + syscall_id: SyscallId, + arg0: usize, + arg1: usize, + arg2: usize, + arg3: usize, + arg4: usize, + arg5: usize, +) -> i32 { let id = syscall_id as usize; let mut ret: i32; let mut failed: i32 = 0; unsafe { #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] - asm!("ecall" + asm!("ecall" : "={x10}" (ret) : "{x17}" (id), "{x10}" (arg0), "{x11}" (arg1), "{x12}" (arg2), "{x13}" (arg3), "{x14}" (arg4), "{x15}" (arg5) : "memory" : "volatile"); #[cfg(target_arch = "x86")] - asm!("int 0x80" + asm!("int 0x80" : "={eax}" (ret) : "{eax}" (id), "{edx}" (arg0), "{ecx}" (arg1), "{ebx}" (arg2), "{edi}" (arg3), "{esi}" (arg4) : "memory" : "intel" "volatile"); #[cfg(target_arch = "x86_64")] - asm!("syscall" + asm!("syscall" : "={rax}" (ret) : "{rax}" (id), "{rdi}" (arg0), "{rsi}" (arg1), "{rdx}" (arg2), "{r10}" (arg3), "{r8}" (arg4), "{r9}" (arg5) : "rcx" "r11" "memory" : "intel" "volatile"); #[cfg(target_arch = "aarch64")] - asm!("svc 0" + asm!("svc 0" : "={x0}" (ret) : "{x8}" (id), "{x0}" (arg0), "{x1}" (arg1), "{x2}" (arg2), "{x3}" (arg3), "{x4}" (arg4), "{x5}" (arg5) : "memory" @@ -52,7 +60,9 @@ fn sys_call(syscall_id: SyscallId, arg0: usize, arg1: usize, arg2: usize, arg3: pub fn enlarge_heap() { const HEAP_SIZE: usize = 16 * 1024 * 1024; let addr = sys_mmap(0, HEAP_SIZE, 0x3, 0x22, 0, 0) as usize; - unsafe { ALLOCATOR.lock().init(addr, HEAP_SIZE); } + unsafe { + ALLOCATOR.lock().init(addr, HEAP_SIZE); + } } pub fn sys_exit(code: usize) -> ! { @@ -60,9 +70,16 @@ pub fn sys_exit(code: usize) -> ! { unreachable!() } - pub fn sys_exec(name: *const u8, argv: *const *const u8, envp: *const *const u8) -> i32 { - sys_call(SyscallId::Exec, name as usize, argv as usize, envp as usize, 0, 0, 0) + sys_call( + SyscallId::Exec, + name as usize, + argv as usize, + envp as usize, + 0, + 0, + 0, + ) } pub fn sys_write(fd: usize, base: *const u8, len: usize) -> i32 { @@ -79,7 +96,15 @@ pub fn sys_open(path: &str, flags: usize) -> i32 { let end = unsafe { &mut *(path.as_ptr().offset(path.len() as isize) as *mut u8) }; let backup = replace(end, 0); const AT_FDCWD: isize = -100; - let ret = sys_call(SyscallId::Openat, AT_FDCWD as usize, path.as_ptr() as usize, flags, 0, 0, 0); + let ret = sys_call( + SyscallId::Openat, + AT_FDCWD as usize, + path.as_ptr() as usize, + flags, + 0, + 0, + 0, + ); *end = backup; ret } @@ -103,7 +128,15 @@ pub fn sys_vfork() -> i32 { const CLONE_VFORK: usize = 0x00004000; const CLONE_VM: usize = 0x00000100; const SIGCHILD: usize = 17; - sys_call(SyscallId::Clone, CLONE_VFORK | CLONE_VM | SIGCHILD, sp, 0, 0, 0, 0) + sys_call( + SyscallId::Clone, + CLONE_VFORK | CLONE_VM | SIGCHILD, + sp, + 0, + 0, + 0, + 0, + ) } /// Wait the process exit. @@ -136,13 +169,29 @@ pub fn sys_getcwd() -> String { /// Change the current working directory pub fn sys_chdir(path: &str) { let path = String::from(path) + "\0"; - sys_call(SyscallId::Chdir, path.as_bytes().as_ptr() as usize, 0, 0, 0, 0, 0); + sys_call( + SyscallId::Chdir, + path.as_bytes().as_ptr() as usize, + 0, + 0, + 0, + 0, + 0, + ); } /// Check file accessibility pub fn sys_access(path: &str) -> i32 { let path = String::from(path) + "\0"; - sys_call(SyscallId::FAccessAt, -100isize as usize, path.as_bytes().as_ptr() as usize, 0, 0, 0, 0) + sys_call( + SyscallId::FAccessAt, + -100isize as usize, + path.as_bytes().as_ptr() as usize, + 0, + 0, + 0, + 0, + ) } #[repr(C)] @@ -155,9 +204,17 @@ pub struct TimeSpec { pub fn sys_sleep(time: usize) -> i32 { let ts = TimeSpec { sec: time as u64, - nsec: 0 + nsec: 0, }; - sys_call(SyscallId::Sleep, &ts as *const TimeSpec as usize, 0, 0, 0, 0, 0) + sys_call( + SyscallId::Sleep, + &ts as *const TimeSpec as usize, + 0, + 0, + 0, + 0, + 0, + ) } pub fn sys_get_time() -> i32 { @@ -178,10 +235,25 @@ pub fn sys_map_pci_device(vendor: usize, product: usize) -> i32 { pub fn sys_get_paddr(vaddr: &[u64], paddr: &mut [u64]) -> i32 { assert_eq!(vaddr.len(), paddr.len()); - sys_call(SyscallId::GetPaddr, vaddr.as_ptr() as usize, paddr.as_ptr() as usize, vaddr.len(), 0, 0, 0) + sys_call( + SyscallId::GetPaddr, + vaddr.as_ptr() as usize, + paddr.as_ptr() as usize, + vaddr.len(), + 0, + 0, + 0, + ) } -pub fn sys_mmap(addr: usize, len: usize, prot: usize, flags: usize, fd: usize, offset: usize) -> i32 { +pub fn sys_mmap( + addr: usize, + len: usize, + prot: usize, + flags: usize, + fd: usize, + offset: usize, +) -> i32 { sys_call(SyscallId::Mmap, addr, len, prot, flags, fd, offset) } @@ -193,8 +265,23 @@ pub fn sys_setsockopt(fd: usize, level: usize, opt: usize, optval: usize, optlen sys_call(SyscallId::SetSockOpt, fd, level, opt, optval, optlen, 0) } -pub fn sys_sendto(fd: usize, base: *const u8, len: usize, flags: usize, addr: usize, addr_len: usize) -> i32 { - sys_call(SyscallId::SendTo, fd, base as usize, len, flags, addr, addr_len) +pub fn sys_sendto( + fd: usize, + base: *const u8, + len: usize, + flags: usize, + addr: usize, + addr_len: usize, +) -> i32 { + sys_call( + SyscallId::SendTo, + fd, + base as usize, + len, + flags, + addr, + addr_len, + ) } pub fn sys_ioctl(fd: usize, request: usize, arg1: usize) -> i32 {