From 69bb8fb80bf50b183cb2c8bc80b89bd8ff9bf29c Mon Sep 17 00:00:00 2001 From: Egor Karavaev Date: Sun, 11 Jun 2017 00:53:30 +0300 Subject: [PATCH 1/5] Add icmpd daemon, only Echo reply for now. --- Cargo.toml | 6 ++- src/icmpd/error.rs | 80 ++++++++++++++++++++++++++++++ src/icmpd/main.rs | 115 ++++++++++++++++++++++++++++++++++++++++++++ src/icmpd/packet.rs | 100 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 300 insertions(+), 1 deletion(-) create mode 100644 src/icmpd/error.rs create mode 100644 src/icmpd/main.rs create mode 100644 src/icmpd/packet.rs diff --git a/Cargo.toml b/Cargo.toml index 8440d9f3c0..c29a186b3e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,8 +18,12 @@ path = "src/tcpd/main.rs" name = "udpd" path = "src/udpd/main.rs" +[[bin]] +name = "icmpd" +path = "src/icmpd/main.rs" + [dependencies] netutils = { git = "https://github.com/redox-os/netutils.git" } rand = "0.3" -redox_event = "0.1" +redox_event = { path = "../event" } redox_syscall = "0.1" diff --git a/src/icmpd/error.rs b/src/icmpd/error.rs new file mode 100644 index 0000000000..cc939b6072 --- /dev/null +++ b/src/icmpd/error.rs @@ -0,0 +1,80 @@ +use std::result; +use std::fmt; +use syscall::error::Error as SyscallError; +use std::io::Error as IOError; +use std::convert; + +pub enum ParsingError { + NotEnoughData, + IncorrectChecksum, +} + +enum ErrorType { + Syscall(SyscallError), + IOError(IOError), + ParsingError(ParsingError), +} + +pub struct Error { + error_type: ErrorType, + descr: String, +} + +impl Error { + pub fn from_parsing_error>(parsing_error: ParsingError, descr: S) -> Error { + Error { + error_type: ErrorType::ParsingError(parsing_error), + descr: descr.into(), + } + } + pub fn from_syscall_error>(syscall_error: SyscallError, descr: S) -> Error { + Error { + error_type: ErrorType::Syscall(syscall_error), + descr: descr.into(), + } + } + + pub fn from_io_error>(io_error: IOError, descr: S) -> Error { + Error { + error_type: ErrorType::IOError(io_error), + descr: descr.into(), + } + } +} + +impl fmt::Display for ParsingError { + fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { + write!(f, "{}", match *self { + ParsingError::NotEnoughData => "not enough data", + ParsingError::IncorrectChecksum => "checksum error", + }) + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { + match self.error_type { + ErrorType::Syscall(ref syscall_error) => { + write!(f, "{} : syscall error: {}", self.descr, syscall_error) + } + ErrorType::IOError(ref io_error) => { + write!(f, "{} : io error : {}", self.descr, io_error) + } + ErrorType::ParsingError(ref parsign_error) => { + write!(f, + "{} : packet parsing error : {}", + self.descr, + parsign_error) + } + } + } +} + +impl convert::From for Error { + fn from(e: IOError) -> Self { + Error::from_io_error(e, "") + } +} + +pub type Result = result::Result; +pub type ParsingResult = result::Result; diff --git a/src/icmpd/main.rs b/src/icmpd/main.rs new file mode 100644 index 0000000000..4e7c582876 --- /dev/null +++ b/src/icmpd/main.rs @@ -0,0 +1,115 @@ +extern crate event; +extern crate syscall; +extern crate netutils; + +use error::{Result, Error, ParsingError}; +use event::EventQueue; +use netutils::{Ipv4, Ipv4Header, Checksum, n16}; +use packet::{Packet, MutPacket}; +use std::fs::File; +use std::io::{Read, Write}; +use std::os::unix::io::{RawFd, FromRawFd}; +use std::process; +use std::mem; + +mod error; +mod packet; + +const MAX_PACKET_SIZE: usize = 2048; + +fn do_echo_response(in_ip_packet: &Ipv4, + in_icmp_packet: &Packet, + icmp_file: &mut File) + -> Result<()> { + let mut ip_data = vec![0; in_icmp_packet.get_total_data_size()]; + { + let mut out_icmp_packet = + MutPacket::from_bytes(&mut ip_data) + .map_err(|e| Error::from_parsing_error(e, "can't parse empty icmp header"))?; + out_icmp_packet.set_echo_response(); + { + let payload = out_icmp_packet.get_payload(); + let in_payload = in_icmp_packet.get_payload(); + if payload.len() != in_payload.len() { + return Err(Error::from_parsing_error(ParsingError::NotEnoughData, + " can't copy icmp payload to echo response")); + } + //WARNING: copy_from_slice can panic if the slices' lengths are different + payload.copy_from_slice(in_icmp_packet.get_payload()); + } + out_icmp_packet.compute_checksum(); + } + let out_ip_packet = Ipv4 { + header: Ipv4Header { + ver_hlen: 0x45, + services: 0, + len: n16::new((ip_data.len() + mem::size_of::()) as u16), + id: n16::new(0), + flags_fragment: n16::new(0), + ttl: in_ip_packet.header.ttl, + proto: 1, + checksum: Checksum { data: 0 }, + src: in_ip_packet.header.dst, + dst: in_ip_packet.header.src, + }, + options: Vec::new(), + data: ip_data, + }; + icmp_file + .write(&out_ip_packet.to_bytes()) + .map_err(|e| Error::from_io_error(e, " can't send an echo response packet")) + .map(|_| ()) +} + +fn on_icmp_packet(icmp_file: &mut File) -> Result> { + let mut packet_buffer = [0; MAX_PACKET_SIZE]; + loop { + let bytes_readed = + icmp_file + .read(&mut packet_buffer) + .map_err(|e| Error::from_io_error(e, "failed to read a packet from ip:1"))?; + if bytes_readed == 0 { + break; + } + let ip_packet = Ipv4::from_bytes(&packet_buffer[..bytes_readed]) + .ok_or(Error::from_parsing_error(ParsingError::NotEnoughData, + "failed to parse ip header"))?; + let icmp_packet = + Packet::from_bytes(&ip_packet.data) + .map_err(|e| Error::from_parsing_error(e, "failed to parse ICMP packet"))?; + + if icmp_packet.is_echo_request() { + do_echo_response(&ip_packet, &icmp_packet, icmp_file)?; + } + } + Ok(None) +} + +fn run() -> Result<()> { + use syscall::flag::*; + + let icmp_fd = syscall::open("ip:1", O_RDWR | O_NONBLOCK) + .map_err(|e| Error::from_syscall_error(e, "failed to open ip:1"))?; + + if unsafe { syscall::clone(0).unwrap() } != 0 { + return Ok(()); + } + + let mut event_queue = + EventQueue::<(), Error>::new() + .map_err(|e| Error::from_io_error(e, "failed to create event queue"))?; + let mut icmp_file = unsafe { File::from_raw_fd(icmp_fd as RawFd) }; + event_queue + .add(icmp_fd as RawFd, + move |_fd| -> Result> { on_icmp_packet(&mut icmp_file) }) + .map_err(|e| Error::from_io_error(e, "failed to listen to events on ip:1"))?; + event_queue.run() +} + +fn main() { + match run() { + Err(err) => println!("icmpd: {}", err), + _ => {} + } + process::exit(0); +} diff --git a/src/icmpd/packet.rs b/src/icmpd/packet.rs new file mode 100644 index 0000000000..5dddb80e6e --- /dev/null +++ b/src/icmpd/packet.rs @@ -0,0 +1,100 @@ +use error::{ParsingResult, ParsingError}; +use netutils::Checksum; +use std::mem; + +#[repr(packed)] +pub struct Header { + icmp_type: u8, + icmp_code: u8, + crc: u16, +} + +pub struct Packet<'a> { + header: &'a Header, + payload: &'a [u8], +} + +pub struct MutPacket<'a> { + header: &'a mut Header, + payload: &'a mut [u8], +} + +impl<'a> Packet<'a> { + pub fn from_bytes<'b>(bytes: &'b [u8]) -> ParsingResult> + where 'b: 'a + { + if bytes.len() < mem::size_of::
() { + Err(ParsingError::NotEnoughData) + } else { + let (header_bytes, payload_bytes) = bytes.split_at(mem::size_of::
()); + let packet = Packet { + header: unsafe { mem::transmute(header_bytes.as_ptr()) }, + payload: payload_bytes, + }; + if packet.is_checksum_ok() { + Ok(packet) + } else { + Err(ParsingError::IncorrectChecksum) + } + } + } + + fn is_checksum_ok(&self) -> bool { + let header_ptr = self.header as *const Header as usize; + let total_size = self.get_total_data_size(); + let mut crc = unsafe { Checksum::sum(header_ptr, total_size) }; + crc -= u16::from_be(self.header.crc) as usize; + let crc = Checksum::compile(crc); + crc == u16::from_be(self.header.crc) + } + + pub fn is_echo_request(&self) -> bool { + self.header.icmp_type == ECHO_REQUEST_TYPE && self.header.icmp_code == ECHO_REQUEST_CODE + } + + pub fn get_payload(&self) -> &[u8] { + self.payload + } + + pub fn get_total_data_size(&self) -> usize { + mem::size_of::
() + self.payload.len() + } +} + +impl<'a> MutPacket<'a> { + pub fn from_bytes<'b>(bytes: &'b mut [u8]) -> ParsingResult> + where 'b: 'a + { + if bytes.len() < mem::size_of::
() { + Err(ParsingError::NotEnoughData) + } else { + let (header_bytes, payload_bytes) = bytes.split_at_mut(mem::size_of::
()); + Ok(MutPacket { + header: unsafe { mem::transmute(header_bytes.as_ptr()) }, + payload: payload_bytes, + }) + } + } + + pub fn set_echo_response(&mut self) { + self.header.icmp_type = ECHO_RESPONSE_TYPE; + self.header.icmp_code = ECHO_RESPONSE_CODE; + } + + pub fn compute_checksum(&mut self) { + self.header.crc = 0; + let header_ptr = self.header as *mut Header as usize; + let total_size = mem::size_of::
() + self.payload.len(); + let crc = Checksum::compile(unsafe { Checksum::sum(header_ptr, total_size) }); + self.header.crc = crc + } + + pub fn get_payload(&mut self) -> &mut [u8] { + self.payload + } +} + +const ECHO_REQUEST_TYPE: u8 = 8; +const ECHO_REQUEST_CODE: u8 = 0; +const ECHO_RESPONSE_TYPE: u8 = 0; +const ECHO_RESPONSE_CODE: u8 = 0; From 8301ee85a1fc81ffee14c056f0fd341ec819143b Mon Sep 17 00:00:00 2001 From: Egor Karavaev Date: Mon, 12 Jun 2017 00:23:04 +0300 Subject: [PATCH 2/5] Add initial support for icmp scheme. --- src/icmpd/main.rs | 108 ++++------------- src/icmpd/packet.rs | 38 +++++- src/icmpd/scheme.rs | 288 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 347 insertions(+), 87 deletions(-) create mode 100644 src/icmpd/scheme.rs diff --git a/src/icmpd/main.rs b/src/icmpd/main.rs index 4e7c582876..2623547228 100644 --- a/src/icmpd/main.rs +++ b/src/icmpd/main.rs @@ -2,114 +2,58 @@ extern crate event; extern crate syscall; extern crate netutils; -use error::{Result, Error, ParsingError}; +use error::{Result, Error}; use event::EventQueue; -use netutils::{Ipv4, Ipv4Header, Checksum, n16}; -use packet::{Packet, MutPacket}; +use scheme::Icmpd; +use std::cell::RefCell; use std::fs::File; -use std::io::{Read, Write}; use std::os::unix::io::{RawFd, FromRawFd}; use std::process; -use std::mem; +use std::rc::Rc; mod error; mod packet; - -const MAX_PACKET_SIZE: usize = 2048; - -fn do_echo_response(in_ip_packet: &Ipv4, - in_icmp_packet: &Packet, - icmp_file: &mut File) - -> Result<()> { - let mut ip_data = vec![0; in_icmp_packet.get_total_data_size()]; - { - let mut out_icmp_packet = - MutPacket::from_bytes(&mut ip_data) - .map_err(|e| Error::from_parsing_error(e, "can't parse empty icmp header"))?; - out_icmp_packet.set_echo_response(); - { - let payload = out_icmp_packet.get_payload(); - let in_payload = in_icmp_packet.get_payload(); - if payload.len() != in_payload.len() { - return Err(Error::from_parsing_error(ParsingError::NotEnoughData, - " can't copy icmp payload to echo response")); - } - //WARNING: copy_from_slice can panic if the slices' lengths are different - payload.copy_from_slice(in_icmp_packet.get_payload()); - } - out_icmp_packet.compute_checksum(); - } - let out_ip_packet = Ipv4 { - header: Ipv4Header { - ver_hlen: 0x45, - services: 0, - len: n16::new((ip_data.len() + mem::size_of::()) as u16), - id: n16::new(0), - flags_fragment: n16::new(0), - ttl: in_ip_packet.header.ttl, - proto: 1, - checksum: Checksum { data: 0 }, - src: in_ip_packet.header.dst, - dst: in_ip_packet.header.src, - }, - options: Vec::new(), - data: ip_data, - }; - icmp_file - .write(&out_ip_packet.to_bytes()) - .map_err(|e| Error::from_io_error(e, " can't send an echo response packet")) - .map(|_| ()) -} - -fn on_icmp_packet(icmp_file: &mut File) -> Result> { - let mut packet_buffer = [0; MAX_PACKET_SIZE]; - loop { - let bytes_readed = - icmp_file - .read(&mut packet_buffer) - .map_err(|e| Error::from_io_error(e, "failed to read a packet from ip:1"))?; - if bytes_readed == 0 { - break; - } - let ip_packet = Ipv4::from_bytes(&packet_buffer[..bytes_readed]) - .ok_or(Error::from_parsing_error(ParsingError::NotEnoughData, - "failed to parse ip header"))?; - let icmp_packet = - Packet::from_bytes(&ip_packet.data) - .map_err(|e| Error::from_parsing_error(e, "failed to parse ICMP packet"))?; - - if icmp_packet.is_echo_request() { - do_echo_response(&ip_packet, &icmp_packet, icmp_file)?; - } - } - Ok(None) -} +mod scheme; fn run() -> Result<()> { use syscall::flag::*; let icmp_fd = syscall::open("ip:1", O_RDWR | O_NONBLOCK) - .map_err(|e| Error::from_syscall_error(e, "failed to open ip:1"))?; + .map_err(|e| Error::from_syscall_error(e, "failed to open ip:1"))? as + RawFd; + + let scheme_fd = syscall::open(":icmp", O_RDWR | O_CREAT | O_NONBLOCK) + .map_err(|e| Error::from_syscall_error(e, "failed to open :icmp"))? as + RawFd; if unsafe { syscall::clone(0).unwrap() } != 0 { return Ok(()); } + let icmpd = Rc::new(RefCell::new(Icmpd::new(unsafe { File::from_raw_fd(icmp_fd) }, + unsafe { File::from_raw_fd(scheme_fd) }))); + let mut event_queue = EventQueue::<(), Error>::new() .map_err(|e| Error::from_io_error(e, "failed to create event queue"))?; - let mut icmp_file = unsafe { File::from_raw_fd(icmp_fd as RawFd) }; + + let icmpd_ = icmpd.clone(); + event_queue - .add(icmp_fd as RawFd, - move |_fd| -> Result> { on_icmp_packet(&mut icmp_file) }) + .add(icmp_fd, move |_fd| icmpd_.borrow_mut().on_icmp_packet()) .map_err(|e| Error::from_io_error(e, "failed to listen to events on ip:1"))?; + + event_queue + .add(scheme_fd, move |_fd| icmpd.borrow_mut().on_scheme_event()) + .map_err(|e| Error::from_io_error(e, "failed to listen to events on icmp"))?; + event_queue.run() } fn main() { - match run() { - Err(err) => println!("icmpd: {}", err), - _ => {} + if let Err(err) = run() { + println!("icmpd: {}", err); + process::exit(1); } process::exit(0); } diff --git a/src/icmpd/packet.rs b/src/icmpd/packet.rs index 5dddb80e6e..fb35ce745a 100644 --- a/src/icmpd/packet.rs +++ b/src/icmpd/packet.rs @@ -19,6 +19,15 @@ pub struct MutPacket<'a> { payload: &'a mut [u8], } +pub enum PacketKind { + EchoRequest, + EchoResponse, + HostUnreachable, + PortUnreachable, + ProtoUnreachable, + Unknown, +} + impl<'a> Packet<'a> { pub fn from_bytes<'b>(bytes: &'b [u8]) -> ParsingResult> where 'b: 'a @@ -48,8 +57,15 @@ impl<'a> Packet<'a> { crc == u16::from_be(self.header.crc) } - pub fn is_echo_request(&self) -> bool { - self.header.icmp_type == ECHO_REQUEST_TYPE && self.header.icmp_code == ECHO_REQUEST_CODE + pub fn get_kind(&self) -> PacketKind { + match (self.header.icmp_type, self.header.icmp_code) { + (ECHO_REQUEST_TYPE, ECHO_REQUEST_CODE) => PacketKind::EchoRequest, + (ECHO_RESPONSE_TYPE, ECHO_RESPONSE_CODE) => PacketKind::EchoResponse, + (UNREACHABLE_TYPE, UNREACHABLE_HOST_CODE) => PacketKind::HostUnreachable, + (UNREACHABLE_TYPE, UNREACHABLE_PROTO_CODE) => PacketKind::ProtoUnreachable, + (UNREACHABLE_TYPE, UNREACHABLE_PORT_CODE) => PacketKind::PortUnreachable, + _ => PacketKind::Unknown, + } } pub fn get_payload(&self) -> &[u8] { @@ -76,9 +92,17 @@ impl<'a> MutPacket<'a> { } } - pub fn set_echo_response(&mut self) { - self.header.icmp_type = ECHO_RESPONSE_TYPE; - self.header.icmp_code = ECHO_RESPONSE_CODE; + pub fn set_kind(&mut self, packet_type: PacketKind) { + let (new_type, new_code) = match packet_type { + EchoRequest => (ECHO_REQUEST_TYPE, ECHO_REQUEST_CODE), + EchoResponse => (ECHO_RESPONSE_TYPE, ECHO_RESPONSE_CODE), + HostUnreachable => (UNREACHABLE_TYPE, UNREACHABLE_HOST_CODE), + PortUnreachable => (UNREACHABLE_TYPE, UNREACHABLE_PORT_CODE), + ProtoUnreachable => (UNREACHABLE_TYPE, UNREACHABLE_PROTO_CODE), + Unknown => (self.header.icmp_type, self.header.icmp_code), + }; + self.header.icmp_type = new_type; + self.header.icmp_code = new_code; } pub fn compute_checksum(&mut self) { @@ -98,3 +122,7 @@ const ECHO_REQUEST_TYPE: u8 = 8; const ECHO_REQUEST_CODE: u8 = 0; const ECHO_RESPONSE_TYPE: u8 = 0; const ECHO_RESPONSE_CODE: u8 = 0; +const UNREACHABLE_TYPE: u8 = 3; +const UNREACHABLE_HOST_CODE: u8 = 1; +const UNREACHABLE_PROTO_CODE: u8 = 2; +const UNREACHABLE_PORT_CODE: u8 = 3; diff --git a/src/icmpd/scheme.rs b/src/icmpd/scheme.rs new file mode 100644 index 0000000000..22616f6f67 --- /dev/null +++ b/src/icmpd/scheme.rs @@ -0,0 +1,288 @@ +use error::{Result, Error, ParsingError}; +use netutils::{Ipv4, Ipv4Header, Checksum, n16}; +use netutils; +use packet::{Header, Packet, MutPacket, PacketKind}; +use std::collections::{BTreeMap, HashSet, VecDeque}; +use std::fs::File; +use std::io::{Read, Write}; +use std::mem; +use std::net::Ipv4Addr; +use syscall::SchemeMut; +use syscall; + +//Some reasonable limits, 65k is a waste of memory +const MAX_PACKET_SIZE: usize = 2048; +const MAX_ICMP_PAYLOAD_SIZE: usize = 2000; + +enum HandleType { + Echo, +} + +struct Handle { + handle_type: HandleType, + events: usize, + flags: usize, + ip_addr: Ipv4Addr, + payload_queue: VecDeque>, +} + +impl Handle { + pub fn new(handle_type: HandleType, ip_addr: Ipv4Addr, flags: usize) -> Handle { + Handle { + handle_type, + events: 0, + ip_addr, + payload_queue: VecDeque::new(), + flags, + } + } +} + +pub struct Icmpd { + icmp_file: File, + scheme_file: File, + next_fd: usize, + echo_ips: BTreeMap>, + handles: BTreeMap, +} + +impl Icmpd { + pub fn new(icmp_file: File, scheme_file: File) -> Icmpd { + Icmpd { + icmp_file, + scheme_file, + next_fd: 0, + echo_ips: BTreeMap::new(), + handles: BTreeMap::new(), + } + } + + pub fn on_scheme_event(&mut self) -> Result> { + loop { + let mut packet = syscall::Packet::default(); + if self.scheme_file.read(&mut packet)? == 0 { + break; + } + self.handle(&mut packet); + } + Ok(None) + } + + pub fn on_icmp_packet(&mut self) -> Result> { + let mut packet_buffer = [0; MAX_PACKET_SIZE]; + loop { + let bytes_readed = + self.icmp_file + .read(&mut packet_buffer) + .map_err(|e| Error::from_io_error(e, "failed to read a packet from ip:1"))?; + if bytes_readed == 0 { + break; + } + let ip_packet = Ipv4::from_bytes(&packet_buffer[..bytes_readed]) + .ok_or(Error::from_parsing_error(ParsingError::NotEnoughData, + "failed to parse ip header"))?; + let icmp_packet = + Packet::from_bytes(&ip_packet.data) + .map_err(|e| Error::from_parsing_error(e, "failed to parse ICMP packet"))?; + + match icmp_packet.get_kind() { + PacketKind::EchoRequest => self.on_echo_request(&ip_packet, &icmp_packet)?, + PacketKind::EchoResponse => self.on_echo_response(&ip_packet, &icmp_packet)?, + _ => (), + } + } + Ok(None) + } + + fn on_echo_request(&mut self, ip_packet: &Ipv4, icmp_packet: &Packet) -> Result<()> { + let echo_response = produce_icmp_packet(Ipv4Addr::from(ip_packet.header.src.bytes), + PacketKind::EchoResponse, + icmp_packet.get_payload())?; + self.icmp_file + .write(&echo_response) + .map_err(|e| Error::from_io_error(e, " can't send an echo response packet")) + .map(|_| ()) + } + + fn on_echo_response(&mut self, ip_packet: &Ipv4, icmp_packet: &Packet) -> Result<()> { + if let Some(fd_set) = self.echo_ips + .get_mut(&Ipv4Addr::from(ip_packet.header.src.bytes)) { + for fd in fd_set.iter() { + if let Some(handle) = self.handles.get_mut(fd) { + handle + .payload_queue + .push_back(Vec::from(icmp_packet.get_payload())); + post_fevent(&mut self.scheme_file, + *fd, + syscall::EVENT_READ, + icmp_packet.get_payload().len())?; + } + } + } + Ok(()) + } + + fn open_echo(&mut self, ip_addr: Ipv4Addr, flags: usize) -> syscall::Result { + let fd = self.next_fd; + self.next_fd += 1; + let handle = Handle::new(HandleType::Echo, ip_addr, flags); + self.handles.insert(fd, handle); + self.echo_ips + .entry(ip_addr) + .or_insert_with(|| HashSet::new()) + .insert(fd); + Ok(fd) + } + + fn read_echo(handle: &mut Handle, buf: &mut [u8]) -> syscall::Result { + if let Some(payload) = handle.payload_queue.pop_front() { + //TODO replace with a proper memcpy + let mut i = 0; + while i < buf.len() && i < payload.len() { + buf[i] = payload[i]; + i += 1; + } + Ok(i) + } else { + Ok(0) + } + } +} + +impl SchemeMut for Icmpd { + fn open(&mut self, url: &[u8], flags: usize, _uid: u32, _gid: u32) -> syscall::Result { + use std::str; + use std::str::FromStr; + + // if uid != 0 { + // return Err(syscall::Error::new(syscall::EACCES)); + // } + + let path = str::from_utf8(url) + .or(Err(syscall::Error::new(syscall::EINVAL)))?; + let mut parts = path.split("/"); + let method = parts.next().ok_or(syscall::Error::new(syscall::EINVAL))?; + match method { + "echo" => { + let addr = parts.next().ok_or(syscall::Error::new(syscall::EINVAL))?; + let addr = Ipv4Addr::from_str(&addr) + .map_err(|_| syscall::Error::new(syscall::EINVAL))?; + self.open_echo(addr, flags) + } + _ => Err(syscall::Error::new(syscall::EINVAL)), + } + } + + fn close(&mut self, fd: usize) -> syscall::Result { + let (ip, ip_set) = { + let handle = self.handles + .get_mut(&fd) + .ok_or(syscall::Error::new(syscall::EBADF))?; + match handle.handle_type { + HandleType::Echo => (handle.ip_addr, &mut self.echo_ips), + } + }; + self.handles.remove(&fd); + let remove_ip = if let Some(fd_set) = ip_set.get_mut(&ip) { + fd_set.remove(&fd); + fd_set.is_empty() + } else { + false + }; + + if remove_ip { + ip_set.remove(&ip); + } + + Ok(0) + } + + fn write(&mut self, fd: usize, buf: &[u8]) -> syscall::Result { + if buf.len() > MAX_ICMP_PAYLOAD_SIZE { + return Err(syscall::Error::new(syscall::EMSGSIZE)); + } + let handle = self.handles + .get_mut(&fd) + .ok_or(syscall::Error::new(syscall::EBADF))?; + match handle.handle_type { + HandleType::Echo => { + let echo_request = + produce_icmp_packet(handle.ip_addr, PacketKind::EchoRequest, buf) + .map_err(|_| syscall::Error::new(syscall::EPROTO))?; + self.icmp_file + .write(&echo_request) + .map_err(|_| syscall::Error::new(syscall::EPROTO)) + } + } + } + + fn read(&mut self, fd: usize, buf: &mut [u8]) -> syscall::Result { + let handle = self.handles + .get_mut(&fd) + .ok_or(syscall::Error::new(syscall::EBADF))?; + match handle.handle_type { + HandleType::Echo => Icmpd::read_echo(handle, buf), + } + } + + fn fevent(&mut self, fd: usize, events: usize) -> syscall::Result { + let handle = self.handles + .get_mut(&fd) + .ok_or(syscall::Error::new(syscall::EBADF))?; + handle.events = events; + Ok(fd) + } +} + +fn produce_icmp_packet(to_ip: Ipv4Addr, kind: PacketKind, payload: &[u8]) -> Result> { + let mut ip_data = vec![0; mem::size_of::
() + payload.len()]; + { + let mut out_icmp_packet = + MutPacket::from_bytes(&mut ip_data) + .map_err(|e| Error::from_parsing_error(e, "can't parse empty icmp header"))?; + out_icmp_packet.set_kind(kind); + { + let out_payload = out_icmp_packet.get_payload(); + if out_payload.len() != payload.len() { + return Err(Error::from_parsing_error(ParsingError::NotEnoughData, + " can't copy icmp payload to echo response")); + } + //WARNING: copy_from_slice can panic if the slices' lengths are different + out_payload.copy_from_slice(payload); + } + out_icmp_packet.compute_checksum(); + } + let out_ip_packet = Ipv4 { + header: Ipv4Header { + ver_hlen: 0x45, + services: 0, + len: n16::new((ip_data.len() + mem::size_of::()) as u16), + id: n16::new(0), + flags_fragment: n16::new(0), + ttl: 64, + proto: 1, + checksum: Checksum { data: 0 }, + src: netutils::Ipv4Addr::NULL, + dst: netutils::Ipv4Addr { bytes: to_ip.octets() }, + }, + options: Vec::new(), + data: ip_data, + }; + Ok(out_ip_packet.to_bytes()) +} + +fn post_fevent(scheme_file: &mut File, fd: usize, event: usize, data_len: usize) -> Result<()> { + scheme_file + .write(&syscall::Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: fd, + c: event, + d: data_len, + }) + .map(|_| ()) + .map_err(|e| Error::from_io_error(e, "failed to post fevent")) +} From 47563fa29ebaf75650b85f8fed7a77b05b55cb64 Mon Sep 17 00:00:00 2001 From: Egor Karavaev Date: Mon, 12 Jun 2017 15:25:15 +0300 Subject: [PATCH 3/5] Add support for Echo sub-header. --- src/icmpd/error.rs | 30 +++++++---- src/icmpd/main.rs | 22 +++++++- src/icmpd/packet.rs | 123 ++++++++++++++++++++++++++++++++++++++------ src/icmpd/scheme.rs | 48 +++++++++++------ 4 files changed, 180 insertions(+), 43 deletions(-) diff --git a/src/icmpd/error.rs b/src/icmpd/error.rs index cc939b6072..ae8007e961 100644 --- a/src/icmpd/error.rs +++ b/src/icmpd/error.rs @@ -4,15 +4,17 @@ use syscall::error::Error as SyscallError; use std::io::Error as IOError; use std::convert; -pub enum ParsingError { +pub enum PacketError { NotEnoughData, IncorrectChecksum, + NoEchoHeader, + SubheaderAlreadPresent, } enum ErrorType { Syscall(SyscallError), IOError(IOError), - ParsingError(ParsingError), + PacketError(PacketError), } pub struct Error { @@ -21,9 +23,9 @@ pub struct Error { } impl Error { - pub fn from_parsing_error>(parsing_error: ParsingError, descr: S) -> Error { + pub fn from_parsing_error>(parsing_error: PacketError, descr: S) -> Error { Error { - error_type: ErrorType::ParsingError(parsing_error), + error_type: ErrorType::PacketError(parsing_error), descr: descr.into(), } } @@ -40,13 +42,23 @@ impl Error { descr: descr.into(), } } + + pub fn is_unrecoverable(&self) -> bool { + match self.error_type { + ErrorType::PacketError(_) => false, + ErrorType::IOError(_) | + ErrorType::Syscall(_) => true, + } + } } -impl fmt::Display for ParsingError { +impl fmt::Display for PacketError { fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { write!(f, "{}", match *self { - ParsingError::NotEnoughData => "not enough data", - ParsingError::IncorrectChecksum => "checksum error", + PacketError::NotEnoughData => "not enough data", + PacketError::IncorrectChecksum => "checksum error", + PacketError::NoEchoHeader => "echo header is missing", + PacketError::SubheaderAlreadPresent => "subheader is already present", }) } } @@ -60,7 +72,7 @@ impl fmt::Display for Error { ErrorType::IOError(ref io_error) => { write!(f, "{} : io error : {}", self.descr, io_error) } - ErrorType::ParsingError(ref parsign_error) => { + ErrorType::PacketError(ref parsign_error) => { write!(f, "{} : packet parsing error : {}", self.descr, @@ -77,4 +89,4 @@ impl convert::From for Error { } pub type Result = result::Result; -pub type ParsingResult = result::Result; +pub type PacketResult = result::Result; diff --git a/src/icmpd/main.rs b/src/icmpd/main.rs index 2623547228..f44089e1f5 100644 --- a/src/icmpd/main.rs +++ b/src/icmpd/main.rs @@ -40,11 +40,29 @@ fn run() -> Result<()> { let icmpd_ = icmpd.clone(); event_queue - .add(icmp_fd, move |_fd| icmpd_.borrow_mut().on_icmp_packet()) + .add(icmp_fd, move |_fd| { + if let Err(err) = icmpd_.borrow_mut().on_icmp_packet() { + if err.is_unrecoverable() { + return Err(err); + } else { + println!("icmpd: network error: {}", err); + } + } + Ok(None) + }) .map_err(|e| Error::from_io_error(e, "failed to listen to events on ip:1"))?; event_queue - .add(scheme_fd, move |_fd| icmpd.borrow_mut().on_scheme_event()) + .add(scheme_fd, move |_fd| { + if let Err(err) = icmpd.borrow_mut().on_scheme_event() { + if err.is_unrecoverable() { + return Err(err); + } else { + println!("icmpd: scheme error: {}", err); + } + } + Ok(None) + }) .map_err(|e| Error::from_io_error(e, "failed to listen to events on icmp"))?; event_queue.run() diff --git a/src/icmpd/packet.rs b/src/icmpd/packet.rs index fb35ce745a..fea7e9cfca 100644 --- a/src/icmpd/packet.rs +++ b/src/icmpd/packet.rs @@ -1,4 +1,4 @@ -use error::{ParsingResult, ParsingError}; +use error::{PacketResult, PacketError}; use netutils::Checksum; use std::mem; @@ -9,14 +9,28 @@ pub struct Header { crc: u16, } +#[derive(Copy, Clone)] +#[repr(packed)] +pub struct EchoHeader { + id: u16, + seq: u16, +} + +pub enum SubHeader<'a> { + Echo(&'a EchoHeader), + None, +} + pub struct Packet<'a> { header: &'a Header, payload: &'a [u8], + subheader: SubHeader<'a>, } pub struct MutPacket<'a> { header: &'a mut Header, payload: &'a mut [u8], + subheader: SubHeader<'a>, } pub enum PacketKind { @@ -28,22 +42,61 @@ pub enum PacketKind { Unknown, } +impl EchoHeader { + pub fn new(id: u16, seq: u16) -> EchoHeader { + EchoHeader { + id: id.to_be(), + seq: seq.to_be(), + } + } + + pub fn get_id(&self) -> u16 { + u16::from_be(self.id) + } + + pub fn get_seq(&self) -> u16 { + u16::from_be(self.seq) + } +} + +impl<'a> SubHeader<'a> { + pub fn get_size(&self) -> usize { + match *self { + SubHeader::None => 0, + SubHeader::Echo(_) => mem::size_of::(), + } + } +} + impl<'a> Packet<'a> { - pub fn from_bytes<'b>(bytes: &'b [u8]) -> ParsingResult> + pub fn from_bytes<'b>(bytes: &'b [u8]) -> PacketResult> where 'b: 'a { if bytes.len() < mem::size_of::
() { - Err(ParsingError::NotEnoughData) + Err(PacketError::NotEnoughData) } else { let (header_bytes, payload_bytes) = bytes.split_at(mem::size_of::
()); - let packet = Packet { + let mut packet = Packet { header: unsafe { mem::transmute(header_bytes.as_ptr()) }, payload: payload_bytes, + subheader: SubHeader::None, }; - if packet.is_checksum_ok() { - Ok(packet) - } else { - Err(ParsingError::IncorrectChecksum) + if !packet.is_checksum_ok() { + return Err(PacketError::IncorrectChecksum); + } + match packet.get_kind() { + PacketKind::EchoResponse => { + if packet.payload.len() < mem::size_of::() { + return Err(PacketError::NoEchoHeader); + } + let (echo_header_payload, payload) = + packet.payload.split_at(mem::size_of::()); + packet.subheader = + SubHeader::Echo(unsafe { mem::transmute(echo_header_payload.as_ptr()) }); + packet.payload = payload; + Ok(packet) + } + _ => Ok(packet), } } } @@ -73,33 +126,65 @@ impl<'a> Packet<'a> { } pub fn get_total_data_size(&self) -> usize { - mem::size_of::
() + self.payload.len() + mem::size_of::
() + self.subheader.get_size() + self.payload.len() + } + + pub fn get_subheader(&self) -> &SubHeader<'a> { + &self.subheader } } impl<'a> MutPacket<'a> { - pub fn from_bytes<'b>(bytes: &'b mut [u8]) -> ParsingResult> + pub fn from_bytes<'b>(bytes: &'b mut [u8]) -> PacketResult> where 'b: 'a { if bytes.len() < mem::size_of::
() { - Err(ParsingError::NotEnoughData) + Err(PacketError::NotEnoughData) } else { let (header_bytes, payload_bytes) = bytes.split_at_mut(mem::size_of::
()); Ok(MutPacket { header: unsafe { mem::transmute(header_bytes.as_ptr()) }, payload: payload_bytes, + subheader: SubHeader::None, }) } } + pub fn set_subheader(self, subheader: &SubHeader) -> PacketResult> { + match self.subheader { + SubHeader::None => {} + _ => return Err(PacketError::SubheaderAlreadPresent), + }; + + if self.payload.len() < subheader.get_size() { + return Err(PacketError::NotEnoughData); + } + + let (subheader_bytes, new_payload) = self.payload.split_at_mut(subheader.get_size()); + let new_subheader = match *subheader { + SubHeader::Echo(echo_sub_header) => { + let echo_sub_header_mut: &mut EchoHeader = + unsafe { mem::transmute(subheader_bytes.as_ptr()) }; + *echo_sub_header_mut = echo_sub_header.clone(); + SubHeader::Echo(echo_sub_header_mut) + } + SubHeader::None => SubHeader::None, + }; + Ok(MutPacket { + header: self.header, + payload: new_payload, + subheader: new_subheader, + }) + } + pub fn set_kind(&mut self, packet_type: PacketKind) { let (new_type, new_code) = match packet_type { - EchoRequest => (ECHO_REQUEST_TYPE, ECHO_REQUEST_CODE), - EchoResponse => (ECHO_RESPONSE_TYPE, ECHO_RESPONSE_CODE), - HostUnreachable => (UNREACHABLE_TYPE, UNREACHABLE_HOST_CODE), - PortUnreachable => (UNREACHABLE_TYPE, UNREACHABLE_PORT_CODE), - ProtoUnreachable => (UNREACHABLE_TYPE, UNREACHABLE_PROTO_CODE), - Unknown => (self.header.icmp_type, self.header.icmp_code), + PacketKind::EchoRequest => (ECHO_REQUEST_TYPE, ECHO_REQUEST_CODE), + PacketKind::EchoResponse => (ECHO_RESPONSE_TYPE, ECHO_RESPONSE_CODE), + PacketKind::HostUnreachable => (UNREACHABLE_TYPE, UNREACHABLE_HOST_CODE), + PacketKind::PortUnreachable => (UNREACHABLE_TYPE, UNREACHABLE_PORT_CODE), + PacketKind::ProtoUnreachable => (UNREACHABLE_TYPE, UNREACHABLE_PROTO_CODE), + PacketKind::Unknown => (self.header.icmp_type, self.header.icmp_code), }; self.header.icmp_type = new_type; self.header.icmp_code = new_code; @@ -116,6 +201,10 @@ impl<'a> MutPacket<'a> { pub fn get_payload(&mut self) -> &mut [u8] { self.payload } + + pub fn get_total_header_size(subheader: &SubHeader) -> usize { + mem::size_of::
() + subheader.get_size() + } } const ECHO_REQUEST_TYPE: u8 = 8; diff --git a/src/icmpd/scheme.rs b/src/icmpd/scheme.rs index 22616f6f67..e943f31a7d 100644 --- a/src/icmpd/scheme.rs +++ b/src/icmpd/scheme.rs @@ -1,7 +1,7 @@ -use error::{Result, Error, ParsingError}; +use error::{Result, Error, PacketError}; use netutils::{Ipv4, Ipv4Header, Checksum, n16}; use netutils; -use packet::{Header, Packet, MutPacket, PacketKind}; +use packet::{Header, Packet, MutPacket, PacketKind, SubHeader, EchoHeader}; use std::collections::{BTreeMap, HashSet, VecDeque}; use std::fs::File; use std::io::{Read, Write}; @@ -24,6 +24,7 @@ struct Handle { flags: usize, ip_addr: Ipv4Addr, payload_queue: VecDeque>, + seq: u16, } impl Handle { @@ -34,6 +35,7 @@ impl Handle { ip_addr, payload_queue: VecDeque::new(), flags, + seq: 0, } } } @@ -79,7 +81,7 @@ impl Icmpd { break; } let ip_packet = Ipv4::from_bytes(&packet_buffer[..bytes_readed]) - .ok_or(Error::from_parsing_error(ParsingError::NotEnoughData, + .ok_or(Error::from_parsing_error(PacketError::NotEnoughData, "failed to parse ip header"))?; let icmp_packet = Packet::from_bytes(&ip_packet.data) @@ -97,6 +99,7 @@ impl Icmpd { fn on_echo_request(&mut self, ip_packet: &Ipv4, icmp_packet: &Packet) -> Result<()> { let echo_response = produce_icmp_packet(Ipv4Addr::from(ip_packet.header.src.bytes), PacketKind::EchoResponse, + &SubHeader::None, icmp_packet.get_payload())?; self.icmp_file .write(&echo_response) @@ -109,13 +112,17 @@ impl Icmpd { .get_mut(&Ipv4Addr::from(ip_packet.header.src.bytes)) { for fd in fd_set.iter() { if let Some(handle) = self.handles.get_mut(fd) { - handle - .payload_queue - .push_back(Vec::from(icmp_packet.get_payload())); - post_fevent(&mut self.scheme_file, - *fd, - syscall::EVENT_READ, - icmp_packet.get_payload().len())?; + if let &SubHeader::Echo(echo_subheader) = icmp_packet.get_subheader() { + if echo_subheader.get_id() == *fd as u16 { + handle + .payload_queue + .push_back(Vec::from(icmp_packet.get_payload())); + post_fevent(&mut self.scheme_file, + *fd, + syscall::EVENT_READ, + icmp_packet.get_payload().len())?; + } + } } } } @@ -207,8 +214,12 @@ impl SchemeMut for Icmpd { match handle.handle_type { HandleType::Echo => { let echo_request = - produce_icmp_packet(handle.ip_addr, PacketKind::EchoRequest, buf) - .map_err(|_| syscall::Error::new(syscall::EPROTO))?; + produce_icmp_packet(handle.ip_addr, + PacketKind::EchoRequest, + &SubHeader::Echo(&EchoHeader::new(fd as u16, handle.seq)), + buf) + .map_err(|_| syscall::Error::new(syscall::EPROTO))?; + handle.seq += 1; self.icmp_file .write(&echo_request) .map_err(|_| syscall::Error::new(syscall::EPROTO)) @@ -234,17 +245,24 @@ impl SchemeMut for Icmpd { } } -fn produce_icmp_packet(to_ip: Ipv4Addr, kind: PacketKind, payload: &[u8]) -> Result> { - let mut ip_data = vec![0; mem::size_of::
() + payload.len()]; +fn produce_icmp_packet(to_ip: Ipv4Addr, + kind: PacketKind, + subheader: &SubHeader, + payload: &[u8]) + -> Result> { + let mut ip_data = vec![0; MutPacket::get_total_header_size(subheader) + payload.len()]; { let mut out_icmp_packet = MutPacket::from_bytes(&mut ip_data) .map_err(|e| Error::from_parsing_error(e, "can't parse empty icmp header"))?; + out_icmp_packet = out_icmp_packet + .set_subheader(subheader) + .map_err(|e| Error::from_parsing_error(e, "can't set subheader"))?; out_icmp_packet.set_kind(kind); { let out_payload = out_icmp_packet.get_payload(); if out_payload.len() != payload.len() { - return Err(Error::from_parsing_error(ParsingError::NotEnoughData, + return Err(Error::from_parsing_error(PacketError::NotEnoughData, " can't copy icmp payload to echo response")); } //WARNING: copy_from_slice can panic if the slices' lengths are different From ce69cdbb8fe0340d09e5c09072c29e93130e1728 Mon Sep 17 00:00:00 2001 From: Egor Karavaev Date: Mon, 12 Jun 2017 19:59:25 +0300 Subject: [PATCH 4/5] Add small fix after testing with ping. --- src/icmpd/error.rs | 8 ++++---- src/icmpd/main.rs | 7 ++++--- src/icmpd/packet.rs | 11 +++-------- src/icmpd/scheme.rs | 33 +++++++++++++++------------------ 4 files changed, 26 insertions(+), 33 deletions(-) diff --git a/src/icmpd/error.rs b/src/icmpd/error.rs index ae8007e961..8c94e2af8c 100644 --- a/src/icmpd/error.rs +++ b/src/icmpd/error.rs @@ -1,8 +1,8 @@ -use std::result; -use std::fmt; -use syscall::error::Error as SyscallError; -use std::io::Error as IOError; use std::convert; +use std::fmt; +use std::io::Error as IOError; +use std::result; +use syscall::error::Error as SyscallError; pub enum PacketError { NotEnoughData, diff --git a/src/icmpd/main.rs b/src/icmpd/main.rs index f44089e1f5..4284ae5d87 100644 --- a/src/icmpd/main.rs +++ b/src/icmpd/main.rs @@ -18,6 +18,10 @@ mod scheme; fn run() -> Result<()> { use syscall::flag::*; + if unsafe { syscall::clone(0).unwrap() } != 0 { + return Ok(()); + } + let icmp_fd = syscall::open("ip:1", O_RDWR | O_NONBLOCK) .map_err(|e| Error::from_syscall_error(e, "failed to open ip:1"))? as RawFd; @@ -26,9 +30,6 @@ fn run() -> Result<()> { .map_err(|e| Error::from_syscall_error(e, "failed to open :icmp"))? as RawFd; - if unsafe { syscall::clone(0).unwrap() } != 0 { - return Ok(()); - } let icmpd = Rc::new(RefCell::new(Icmpd::new(unsafe { File::from_raw_fd(icmp_fd) }, unsafe { File::from_raw_fd(scheme_fd) }))); diff --git a/src/icmpd/packet.rs b/src/icmpd/packet.rs index fea7e9cfca..ade4f6e4a0 100644 --- a/src/icmpd/packet.rs +++ b/src/icmpd/packet.rs @@ -13,7 +13,7 @@ pub struct Header { #[repr(packed)] pub struct EchoHeader { id: u16, - seq: u16, + //Seq is set by the caller } pub enum SubHeader<'a> { @@ -43,20 +43,15 @@ pub enum PacketKind { } impl EchoHeader { - pub fn new(id: u16, seq: u16) -> EchoHeader { + pub fn new(id: u16) -> EchoHeader { EchoHeader { id: id.to_be(), - seq: seq.to_be(), } } pub fn get_id(&self) -> u16 { u16::from_be(self.id) } - - pub fn get_seq(&self) -> u16 { - u16::from_be(self.seq) - } } impl<'a> SubHeader<'a> { @@ -193,7 +188,7 @@ impl<'a> MutPacket<'a> { pub fn compute_checksum(&mut self) { self.header.crc = 0; let header_ptr = self.header as *mut Header as usize; - let total_size = mem::size_of::
() + self.payload.len(); + let total_size = Self::get_total_header_size(&self.subheader) + self.payload.len(); let crc = Checksum::compile(unsafe { Checksum::sum(header_ptr, total_size) }); self.header.crc = crc } diff --git a/src/icmpd/scheme.rs b/src/icmpd/scheme.rs index e943f31a7d..1360ea345e 100644 --- a/src/icmpd/scheme.rs +++ b/src/icmpd/scheme.rs @@ -1,7 +1,7 @@ use error::{Result, Error, PacketError}; use netutils::{Ipv4, Ipv4Header, Checksum, n16}; use netutils; -use packet::{Header, Packet, MutPacket, PacketKind, SubHeader, EchoHeader}; +use packet::{Packet, MutPacket, PacketKind, SubHeader, EchoHeader}; use std::collections::{BTreeMap, HashSet, VecDeque}; use std::fs::File; use std::io::{Read, Write}; @@ -24,7 +24,6 @@ struct Handle { flags: usize, ip_addr: Ipv4Addr, payload_queue: VecDeque>, - seq: u16, } impl Handle { @@ -35,7 +34,6 @@ impl Handle { ip_addr, payload_queue: VecDeque::new(), flags, - seq: 0, } } } @@ -66,6 +64,7 @@ impl Icmpd { break; } self.handle(&mut packet); + self.scheme_file.write(&packet)?; } Ok(None) } @@ -108,19 +107,22 @@ impl Icmpd { } fn on_echo_response(&mut self, ip_packet: &Ipv4, icmp_packet: &Packet) -> Result<()> { - if let Some(fd_set) = self.echo_ips - .get_mut(&Ipv4Addr::from(ip_packet.header.src.bytes)) { - for fd in fd_set.iter() { - if let Some(handle) = self.handles.get_mut(fd) { - if let &SubHeader::Echo(echo_subheader) = icmp_packet.get_subheader() { + if let &SubHeader::Echo(echo_subheader) = icmp_packet.get_subheader() { + if let Some(fd_set) = self.echo_ips + .get_mut(&Ipv4Addr::from(ip_packet.header.src.bytes)) { + for fd in fd_set.iter() { + if let Some(handle) = self.handles.get_mut(fd) { if echo_subheader.get_id() == *fd as u16 { handle .payload_queue .push_back(Vec::from(icmp_packet.get_payload())); - post_fevent(&mut self.scheme_file, - *fd, - syscall::EVENT_READ, - icmp_packet.get_payload().len())?; + + if handle.events & syscall::EVENT_READ == syscall::EVENT_READ { + post_fevent(&mut self.scheme_file, + *fd, + syscall::EVENT_READ, + icmp_packet.get_payload().len())?; + } } } } @@ -161,10 +163,6 @@ impl SchemeMut for Icmpd { use std::str; use std::str::FromStr; - // if uid != 0 { - // return Err(syscall::Error::new(syscall::EACCES)); - // } - let path = str::from_utf8(url) .or(Err(syscall::Error::new(syscall::EINVAL)))?; let mut parts = path.split("/"); @@ -216,10 +214,9 @@ impl SchemeMut for Icmpd { let echo_request = produce_icmp_packet(handle.ip_addr, PacketKind::EchoRequest, - &SubHeader::Echo(&EchoHeader::new(fd as u16, handle.seq)), + &SubHeader::Echo(&EchoHeader::new(fd as u16)), buf) .map_err(|_| syscall::Error::new(syscall::EPROTO))?; - handle.seq += 1; self.icmp_file .write(&echo_request) .map_err(|_| syscall::Error::new(syscall::EPROTO)) From 53db52c119ef224f14c7de150da31347bb9ead70 Mon Sep 17 00:00:00 2001 From: Egor Karavaev Date: Tue, 13 Jun 2017 16:23:49 +0300 Subject: [PATCH 5/5] Fix clippy warnings. --- Cargo.toml | 2 +- src/icmpd/packet.rs | 36 +++++++++++++++++------------------ src/icmpd/scheme.rs | 46 +++++++++++++++++++++++++-------------------- 3 files changed, 45 insertions(+), 39 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c29a186b3e..16aa9d1275 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,5 +25,5 @@ path = "src/icmpd/main.rs" [dependencies] netutils = { git = "https://github.com/redox-os/netutils.git" } rand = "0.3" -redox_event = { path = "../event" } +redox_event = { git = "https://github.com/redox-os/event.git" } redox_syscall = "0.1" diff --git a/src/icmpd/packet.rs b/src/icmpd/packet.rs index ade4f6e4a0..0426d61d90 100644 --- a/src/icmpd/packet.rs +++ b/src/icmpd/packet.rs @@ -2,6 +2,15 @@ use error::{PacketResult, PacketError}; use netutils::Checksum; use std::mem; +const ECHO_REQUEST_TYPE: u8 = 8; +const ECHO_REQUEST_CODE: u8 = 0; +const ECHO_RESPONSE_TYPE: u8 = 0; +const ECHO_RESPONSE_CODE: u8 = 0; +const UNREACHABLE_TYPE: u8 = 3; +const UNREACHABLE_HOST_CODE: u8 = 1; +const UNREACHABLE_PROTO_CODE: u8 = 2; +const UNREACHABLE_PORT_CODE: u8 = 3; + #[repr(packed)] pub struct Header { icmp_type: u8, @@ -44,9 +53,7 @@ pub enum PacketKind { impl EchoHeader { pub fn new(id: u16) -> EchoHeader { - EchoHeader { - id: id.to_be(), - } + EchoHeader { id: id.to_be() } } pub fn get_id(&self) -> u16 { @@ -72,7 +79,7 @@ impl<'a> Packet<'a> { } else { let (header_bytes, payload_bytes) = bytes.split_at(mem::size_of::
()); let mut packet = Packet { - header: unsafe { mem::transmute(header_bytes.as_ptr()) }, + header: unsafe { &*(header_bytes.as_ptr() as *const Header) }, payload: payload_bytes, subheader: SubHeader::None, }; @@ -86,8 +93,10 @@ impl<'a> Packet<'a> { } let (echo_header_payload, payload) = packet.payload.split_at(mem::size_of::()); - packet.subheader = - SubHeader::Echo(unsafe { mem::transmute(echo_header_payload.as_ptr()) }); + packet.subheader = SubHeader::Echo(unsafe { + &*(echo_header_payload.as_ptr() as + *const EchoHeader) + }); packet.payload = payload; Ok(packet) } @@ -138,7 +147,7 @@ impl<'a> MutPacket<'a> { } else { let (header_bytes, payload_bytes) = bytes.split_at_mut(mem::size_of::
()); Ok(MutPacket { - header: unsafe { mem::transmute(header_bytes.as_ptr()) }, + header: unsafe { &mut *(header_bytes.as_ptr() as *mut Header) }, payload: payload_bytes, subheader: SubHeader::None, }) @@ -159,8 +168,8 @@ impl<'a> MutPacket<'a> { let new_subheader = match *subheader { SubHeader::Echo(echo_sub_header) => { let echo_sub_header_mut: &mut EchoHeader = - unsafe { mem::transmute(subheader_bytes.as_ptr()) }; - *echo_sub_header_mut = echo_sub_header.clone(); + unsafe { &mut *(subheader_bytes.as_ptr() as *mut EchoHeader) }; + *echo_sub_header_mut = *echo_sub_header; SubHeader::Echo(echo_sub_header_mut) } SubHeader::None => SubHeader::None, @@ -201,12 +210,3 @@ impl<'a> MutPacket<'a> { mem::size_of::
() + subheader.get_size() } } - -const ECHO_REQUEST_TYPE: u8 = 8; -const ECHO_REQUEST_CODE: u8 = 0; -const ECHO_RESPONSE_TYPE: u8 = 0; -const ECHO_RESPONSE_CODE: u8 = 0; -const UNREACHABLE_TYPE: u8 = 3; -const UNREACHABLE_HOST_CODE: u8 = 1; -const UNREACHABLE_PROTO_CODE: u8 = 2; -const UNREACHABLE_PORT_CODE: u8 = 3; diff --git a/src/icmpd/scheme.rs b/src/icmpd/scheme.rs index 1360ea345e..4f42e9a47f 100644 --- a/src/icmpd/scheme.rs +++ b/src/icmpd/scheme.rs @@ -64,7 +64,7 @@ impl Icmpd { break; } self.handle(&mut packet); - self.scheme_file.write(&packet)?; + self.scheme_file.write_all(&packet)?; } Ok(None) } @@ -80,8 +80,10 @@ impl Icmpd { break; } let ip_packet = Ipv4::from_bytes(&packet_buffer[..bytes_readed]) - .ok_or(Error::from_parsing_error(PacketError::NotEnoughData, - "failed to parse ip header"))?; + .ok_or_else(|| { + Error::from_parsing_error(PacketError::NotEnoughData, + "failed to parse ip header") + })?; let icmp_packet = Packet::from_bytes(&ip_packet.data) .map_err(|e| Error::from_parsing_error(e, "failed to parse ICMP packet"))?; @@ -107,7 +109,7 @@ impl Icmpd { } fn on_echo_response(&mut self, ip_packet: &Ipv4, icmp_packet: &Packet) -> Result<()> { - if let &SubHeader::Echo(echo_subheader) = icmp_packet.get_subheader() { + if let SubHeader::Echo(echo_subheader) = *icmp_packet.get_subheader() { if let Some(fd_set) = self.echo_ips .get_mut(&Ipv4Addr::from(ip_packet.header.src.bytes)) { for fd in fd_set.iter() { @@ -138,7 +140,7 @@ impl Icmpd { self.handles.insert(fd, handle); self.echo_ips .entry(ip_addr) - .or_insert_with(|| HashSet::new()) + .or_insert_with(HashSet::new) .insert(fd); Ok(fd) } @@ -164,13 +166,17 @@ impl SchemeMut for Icmpd { use std::str::FromStr; let path = str::from_utf8(url) - .or(Err(syscall::Error::new(syscall::EINVAL)))?; - let mut parts = path.split("/"); - let method = parts.next().ok_or(syscall::Error::new(syscall::EINVAL))?; + .or_else(|_| Err(syscall::Error::new(syscall::EINVAL)))?; + let mut parts = path.split('/'); + let method = parts + .next() + .ok_or_else(|| syscall::Error::new(syscall::EINVAL))?; match method { "echo" => { - let addr = parts.next().ok_or(syscall::Error::new(syscall::EINVAL))?; - let addr = Ipv4Addr::from_str(&addr) + let addr = parts + .next() + .ok_or_else(|| syscall::Error::new(syscall::EINVAL))?; + let addr = Ipv4Addr::from_str(addr) .map_err(|_| syscall::Error::new(syscall::EINVAL))?; self.open_echo(addr, flags) } @@ -182,7 +188,7 @@ impl SchemeMut for Icmpd { let (ip, ip_set) = { let handle = self.handles .get_mut(&fd) - .ok_or(syscall::Error::new(syscall::EBADF))?; + .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; match handle.handle_type { HandleType::Echo => (handle.ip_addr, &mut self.echo_ips), } @@ -208,15 +214,15 @@ impl SchemeMut for Icmpd { } let handle = self.handles .get_mut(&fd) - .ok_or(syscall::Error::new(syscall::EBADF))?; + .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; match handle.handle_type { HandleType::Echo => { - let echo_request = - produce_icmp_packet(handle.ip_addr, - PacketKind::EchoRequest, - &SubHeader::Echo(&EchoHeader::new(fd as u16)), - buf) - .map_err(|_| syscall::Error::new(syscall::EPROTO))?; + let echo_request = produce_icmp_packet(handle.ip_addr, + PacketKind::EchoRequest, + &SubHeader::Echo(&EchoHeader::new(fd as + u16)), + buf) + .map_err(|_| syscall::Error::new(syscall::EPROTO))?; self.icmp_file .write(&echo_request) .map_err(|_| syscall::Error::new(syscall::EPROTO)) @@ -227,7 +233,7 @@ impl SchemeMut for Icmpd { fn read(&mut self, fd: usize, buf: &mut [u8]) -> syscall::Result { let handle = self.handles .get_mut(&fd) - .ok_or(syscall::Error::new(syscall::EBADF))?; + .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; match handle.handle_type { HandleType::Echo => Icmpd::read_echo(handle, buf), } @@ -236,7 +242,7 @@ impl SchemeMut for Icmpd { fn fevent(&mut self, fd: usize, events: usize) -> syscall::Result { let handle = self.handles .get_mut(&fd) - .ok_or(syscall::Error::new(syscall::EBADF))?; + .ok_or_else(|| syscall::Error::new(syscall::EBADF))?; handle.events = events; Ok(fd) }