X-Git-Url: http://git.euphorik.ch/?p=crypto_lab1.git;a=blobdiff_plain;f=lab1_rust%2Fsrc%2Fend_point.rs;fp=lab1_rust%2Fsrc%2Fend_point.rs;h=2d0a66c9e09815cc76a7fffb2efa176ef43dbab8;hp=0000000000000000000000000000000000000000;hb=ecdec5bf7022018eadf4a38b01890bbb3ab79c89;hpb=c9318a07ce0ec00f999ff17943b83048d536ecd1 diff --git a/lab1_rust/src/end_point.rs b/lab1_rust/src/end_point.rs new file mode 100644 index 0000000..2d0a66c --- /dev/null +++ b/lab1_rust/src/end_point.rs @@ -0,0 +1,319 @@ +use std::io; +use std::io::{ MemWriter, Acceptor, Listener, TcpStream, IoResult, IoError, EndOfFile }; +use std::io::net::tcp::{ TcpAcceptor, TcpListener }; +use packet; +use packet::{ Packet, Command, Answer, Error, ReadingResult, PacketType }; + +// Default timeout when waiting data on a stream (for instance: 'TcpStream::read'). +static DEFAULT_TIMEOUT: Option = Some(500); // [ms]. + +pub struct Server { + acceptor: TcpAcceptor +} + +pub struct Client { + end_point: EndPoint, +} + +pub struct EndPoint { + socket: TcpStream, + current_timestamp: u64 +} + +impl Server { + pub fn new(interface: &str, port: u16) -> IoResult { + let mut acceptor = try!(TcpListener::bind(interface, port).listen()); + + let server = Server { + acceptor: acceptor.clone() + }; + + spawn(proc() { + loop { + for stream in acceptor.incoming() { + match stream { + Ok(stream) => spawn(proc() { + Server::handle_client(EndPoint::new(stream)); + }), + _ => return + } + } + } + }); + + Ok(server) + } + + pub fn close(&mut self) -> IoResult<()> { + self.acceptor.close_accept() + } + + fn handle_client(mut end_point: EndPoint) { + loop { + match end_point.read() { + Ok(packet@Packet { t: Command(..), .. }) => { + println!("[Server] Valid command received: {}", packet); + let answer = Answer(Packet::random_packet_data([])); + match end_point.send(answer.clone()) { + Ok(_) => + println!("[Server] Answer sent: {}", answer), + Err(e) => + println!("[Server] Can't send the answer. Error: {}", e) + } + }, + // Socket has been closed. + Err(packet::IOReadError(IoError { kind: EndOfFile, .. })) => { + println!("[Server] Connection closed: EOF"); + return + }, + other => + println!("[Server] Error or invalid packet: {}", other) + } + } + } +} + +impl Client { + pub fn new(address: &str, port: u16) -> IoResult { + Ok(Client { end_point: EndPoint { + socket: try!(TcpStream::connect(address, port)), + current_timestamp: 0 + }}) + } + + pub fn close(&mut self) -> IoResult<()> { + self.end_point.close() + } + + pub fn send(&mut self, packet: PacketType) { + match packet { + Command(_) => { + println!("[Client] Sending: {}", packet); + match self.end_point.send_with_result(packet) { + Ok(Ok(packet@Packet { t: Answer(..), .. })) => + println!("[Client] Command transmitted correctly, answer: {}", packet), + Ok(Ok(packet)) => + println!("[Client] Command transmitted correctly, wrong answer: {}", packet), + Ok(Err(e)) => + println!("[Client] Answer error: {}", e), + Err(e) => + println!("[Client] Can't send the packet. Error: {}", e) + } + }, + other => + println!("[Client] Cannot send this type of packet: {}", other) + } + } + + /// Send some valid and not-valid packets to the server and check the result. + /// For each test a new client is created. + pub fn start_tests(address: &str, port: u16) { + let execute = |f: &mut |&mut Client| -> bool| -> bool { + match Client::new(address, port) { + Ok(ref mut client) => (*f)(client), + Err(e) => { + println!("Unable to create a client. Error: {}", e); + false + } + } + }; + + fn raw_packet(timestamp: u64) -> Vec { + let mut m = MemWriter::new(); + match (Packet { t: Command(Packet::random_packet_data([42])), timestamp: timestamp }).write(&mut m) { + Err(_) => vec!(), + _ => m.unwrap() + } + } + + let mut tests = vec!( + // 1) + |client: &mut Client| -> bool { + println!("Sending a valid packet..."); + match client.end_point.send_with_result(Command(Packet::random_packet_data([42]))) { + Ok(Ok(Packet { t: Answer(..), .. })) => true, + other => { + println!("Error: {}", other); + false + } + } + }, + // 2) + |client: &mut Client| -> bool { + println!("Sending a packet with an unknown type..."); + client.end_point.current_timestamp += 1; + let mut raw_packet = raw_packet(client.end_point.current_timestamp); + raw_packet[2] = 0xEE; // Alter the type. + match client.end_point.send_raw_with_result(raw_packet.as_slice()) { + Ok(Err(packet::IOReadError( IoError { kind: io::TimedOut, .. }))) => true, // OK: the server should not send any packet. + other => { + println!("Error: {}", other); + false + } + } + }, + // 3) + |client: &mut Client| -> bool { + println!("Sending a packet with an old timestamp..."); + client.end_point.current_timestamp += 1; + let raw_packet = raw_packet(0); + match client.end_point.send_raw_with_result(raw_packet.as_slice()) { + Ok(Err(packet::IOReadError( IoError { kind: io::TimedOut, .. }))) => true, // OK: the server should not send any packet. + other => { + println!("Error: {}", other); + false + } + } + }, + // 4) + |client: &mut Client| -> bool { + println!("Sending a packet with altered crypted data (do not alter the padding)..."); + client.end_point.current_timestamp += 1; + let mut raw_packet = raw_packet(client.end_point.current_timestamp); + raw_packet[11] = 0xDE; + raw_packet[12] = 0xAD; + raw_packet[13] = 0xBE; + raw_packet[14] = 0xEF; + match client.end_point.send_raw_with_result(raw_packet.as_slice()) { + Ok(Ok(Packet { t: Error(packet::AuthError), .. })) => true, + other => { + println!("Error: {}", other); + false + } + } + }, + // 5) + |client: &mut Client| -> bool { + println!("Sending a packet with too small data..."); + let command = Command(Packet::new_packet_data(0, Vec::from_elem(6, 0x00))); + match client.end_point.send_with_result(command) { + Ok(Err(packet::IOReadError( IoError { kind: io::TimedOut, .. }))) => true, // OK: the server should not send any packet. + other => { + println!("Error: {}", other); + false + } + } + }, + // 6) + |client: &mut Client| -> bool { + println!("Sending a packet with too large data..."); + let command = Command(Packet::new_packet_data(0, Vec::from_elem(40, 0x00))); + match client.end_point.send_with_result(command) { + Ok(Err(packet::IOReadError( IoError { kind: io::TimedOut, .. }))) => true, // OK: the server should not send any packet. + other => { + println!("Error: {}", other); + false + } + } + }, + // 7) + |client: &mut Client| -> bool { + println!("Sending a packet with wrong padding (all 0)..."); + client.end_point.current_timestamp += 1; + let mut m = MemWriter::new(); + let raw_packet = match (Packet { t: Command(Packet::random_packet_data([42])), timestamp: client.end_point.current_timestamp }).write_with_padding_fun(&mut m, |_, _| -> u8 { 0 }) { + Err(_) => vec!(), + _ => m.unwrap() + }; + + match client.end_point.send_raw_with_result(raw_packet.as_slice()) { + Ok(Ok(Packet { t: Error(packet::CryptError), .. })) => true, + other => { + println!("Error: {}", other); + false + } + } + }, + ); + + let mut nb_test_passed = 0; + for (i, test) in range(1, tests.len()+1).zip(tests.iter_mut()) { + println!("===== Test case #{}:", i) + if execute(test) { + nb_test_passed += 1; + println!("===== Test passed"); + } else { + println!("===== Test failed"); + } + } + + if nb_test_passed == tests.len() { + println!("All tests passed"); + } else { + println!("#{} test(s) failed", tests.len() - nb_test_passed); + } + } +} + +impl EndPoint { + pub fn new(socket: TcpStream) -> EndPoint { + EndPoint { socket: socket, current_timestamp: 0 } + } + + fn close(&mut self) -> IoResult<()> { + try!(self.socket.close_read()); + try!(self.socket.close_write()); + Ok(()) + } + + /// Send a packet and wait for an answer synchronously. + fn send_with_result(&mut self, p: PacketType) -> IoResult { + match self.send(p) { + Err(e) => Err(e), + _ => Ok(self.read()) + } + } + + /// Send arbitrary data and wait for an answer synchronously. + /// Do not increment the current timestamp. + fn send_raw_with_result(&mut self, p: &[u8]) -> IoResult { + self.socket.set_timeout(DEFAULT_TIMEOUT); + match self.socket.write(p) { + Err(e) => Err(e), + _ => Ok(self.read()) + } + } + + fn send(&mut self, p: PacketType) -> IoResult<()> { + self.socket.set_timeout(DEFAULT_TIMEOUT); + self.current_timestamp += 1; + match (Packet { t: p, timestamp: self.current_timestamp }).write(&mut self.socket) { + Err(packet::WriteIOError(e)) => Err(e), + _ => Ok(()) + } + } + + fn read(&mut self) -> ReadingResult { + fn send_error(ep: &mut EndPoint, error_type: packet::ErrorType) { + match ep.send(Error(error_type)) { + Err(e) => println!("Unable to send error packet: {}", e), + Ok(_) => () + }; + }; + + self.socket.set_timeout(DEFAULT_TIMEOUT); + match Packet::read(&mut self.socket) { + Ok(packet) => { + if packet.timestamp <= self.current_timestamp { + println!("Error, timestamp mismatch, current timestamp: {}, packet received: {}", self.current_timestamp, packet); + Err(packet::InvalidTimestampError) + } else { + self.current_timestamp = packet.timestamp + 1; + Ok(packet) + } + }, + e @ Err(packet::PaddingError) => { + self.current_timestamp += 1; + send_error(self, packet::CryptError); + e + }, + e @ Err(packet::MACMismatchError) => { + self.current_timestamp += 1; + send_error(self, packet::AuthError); + e + }, + other => + other + } + } +}