impl Server {
pub fn new(interface: &str, port: u16) -> IoResult<Server> {
let mut acceptor = try!(TcpListener::bind(interface, port).listen());
-
- let server = Server {
+
+ let server = Server {
acceptor: acceptor.clone()
};
-
+
spawn(proc() {
loop {
for stream in acceptor.incoming() {
}
}
});
-
+
Ok(server)
}
-
+
pub fn close(&mut self) -> IoResult<()> {
self.acceptor.close_accept()
}
-
- fn handle_client(mut end_point: EndPoint) {
+
+ fn handle_client(mut end_point: EndPoint) {
loop {
- match end_point.read() {
+ match end_point.read() {
Ok(packet@Packet { t: Command(..), .. }) => {
println!("[Server] Valid command received: {}", packet);
let answer = Answer(Packet::random_packet_data([]));
other =>
println!("[Server] Error or invalid packet: {}", other)
}
- }
+ }
}
}
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] Cannot send this type of packet: {}", other)
}
}
-
+
/// Send some valid and not-valid packets to the server and check the result.
pub fn start_tests(address: &str, port: u16) {
let execute = |f: &mut |&mut Client| -> bool| -> bool {
}
}
};
-
+
+ fn raw_packet(timestamp: u64) -> Vec<u8> {
+ let mut m = MemWriter::new();
+ match (Packet { t: Command(Packet::random_packet_data([42])), timestamp: timestamp }).write(&mut m) {
+ Err(e) => vec!(),
+ _ => m.unwrap()
+ }
+ }
+
let mut tests = vec!(
|client: &mut Client| -> bool {
println!("Send a valid packet...");
match client.end_point.send_with_result(Command(Packet::random_packet_data([42]))) {
- Ok(Ok(packet@Packet { t: Answer(..), .. })) =>
- true,
+ Ok(Ok(packet@Packet { t: Answer(..), .. })) => true,
other => {
println!("Error: {}", other);
false
}
}
},
-
+
|client: &mut Client| -> bool {
println!("Send a packet with an unknown type...");
client.end_point.current_timestamp += 1;
- let mut m = MemWriter::new();
- match (Packet { t: Command(Packet::random_packet_data([42])), timestamp: client.end_point.current_timestamp }).write(&mut m) {
- Err(e) => {
- println!("Error: {}", e)
+ 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: TimedOut, .. }))) => true, // OK: the server should not send any packet.
+ other => {
+ println!("Error: {}", other);
false
- },
- _ => {
- let mut raw_packet = m.unwrap();
- 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: TimedOut, .. }))) => true, // The server should not send a packet.
- other => {
- println!("Error: {}", other);
- false
- }
- }
}
}
- }
+ },
+
+ |client: &mut Client| -> bool {
+ println!("Send 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: TimedOut, .. }))) => true, // OK: the server should not send any packet.
+ other => {
+ println!("Error: {}", other);
+ false
+ }
+ }
+ },
+
+ |client: &mut Client| -> bool {
+ println!("Send a packet with altered crypted data...");
+ 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@Packet { t: Error(packet::AuthError), .. })) => true,
+ other => {
+ println!("Error: {}", other);
+ false
+ }
+ }
+ },
+
+ |client: &mut Client| -> bool {
+ println!("Send a packet with too small data...");
+ let mut 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: TimedOut, .. }))) => true, // OK: the server should not send any packet.
+ other => {
+ println!("Error: {}", other);
+ false
+ }
+ }
+ },
+
+ |client: &mut Client| -> bool {
+ println!("Send a packet with too large data...");
+ let mut 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: TimedOut, .. }))) => true, // OK: the server should not send any packet.
+ other => {
+ println!("Error: {}", other);
+ false
+ }
+ }
+ },
+
+ |client: &mut Client| -> bool {
+ println!("Send a packet with wrong padding...");
+ 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(e) => vec!(),
+ _ => m.unwrap()
+ };
+
+ match client.end_point.send_raw_with_result(raw_packet.as_slice()) {
+ Ok(Ok(packet@Packet { t: Error(packet::CryptError), .. })) => true,
+ other => {
+ println!("Error: {}", other);
+ false
+ }
+ }
+ },
);
-
- for (i, test) in range(0, tests.len()).zip(tests.iter_mut()) {
+
+ 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");
- break;
}
- }
-
- // Send a packet with a wrong timestamp.
- // Send a packet with a maximum timestamp.
- // Send a packet with altered encrypted data.
+ }
+
+ if nb_test_passed == tests.len() {
+ println!("All tests passed");
+ } else {
+ println!("#{} test(s) failed", tests.len() - nb_test_passed);
+ }
}
}
-impl EndPoint {
+impl EndPoint {
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<ReadingResult> {
match self.send(p) {
_ => 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<ReadingResult> {
_ => Ok(self.read())
}
}
-
+
fn send(&mut self, p: PacketType) -> IoResult<()> {
self.socket.set_timeout(DEFAULT_TIMEOUT);
self.current_timestamp += 1;
_ => Ok(())
}
}
-
+
fn read(&mut self) -> ReadingResult {
fn send_error(ep: &mut EndPoint, error_type: packet::ErrorType) {
match ep.send(Error(error_type)) {
Ok(_) => ()
};
};
-
- self.socket.set_timeout(DEFAULT_TIMEOUT);
+
+ self.socket.set_timeout(DEFAULT_TIMEOUT);
match Packet::read(&mut self.socket) {
Ok(packet) => {
if packet.timestamp <= self.current_timestamp {
}
},
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
},
pub enum ReadingError {
IOReadError(io::IoError),
UnknownPacketTypeError, // If the first byte is unknown.
- UnconsistentEncryptedSizeError,
+ UnconsistentEncryptedSizeError,
UnconsistentDataSizeError, // The data size is not valid.
UnconsistentMACSizeError, // The MAC hasn't the correct size.
- MACMismatchError, // The uncrypted received data doesn't match to the received MAC.
- PaddingError, // Padding format error.
+ MACMismatchError, // The uncrypted received data doesn't match to the received MAC.
+ PaddingError, // Padding format error.
DataError, // The data are invalid.
InvalidTimestampError
}
let mut rng = if seed.is_empty() { StdRng::new().unwrap() } else { SeedableRng::from_seed(seed) };
let mut payload = Vec::from_elem(distributions::Range::new(MIN_PAYLOAD_SIZE, MAX_PAYLOAD_SIZE + 1).ind_sample(&mut rng), 0u8);
rng.fill_bytes(payload.as_mut_slice_());
- PacketData {
+ PacketData {
id: rng.gen::<u8>(),
payload: payload
}
}
+ pub fn new_packet_data(id: u8, payload: Vec<u8>) -> PacketData {
+ PacketData { id: id, payload: payload }
+ }
+
pub fn write(&self, output: &mut io::Writer) -> WritingResult {
+ self.write_with_padding_fun(output, |_: uint, padding_length: uint| -> u8 {
+ padding_length as u8
+ })
+ }
+
+ /// 'padd_fun' is function to fill the padding. The first argument is the index of the current byte, starting at 0.
+ /// The second argument is the padding length.
+ pub fn write_with_padding_fun(&self, output: &mut io::Writer, padd_fun: |uint, uint| -> u8) -> WritingResult {
fn packet_data(p: &PacketData) -> Vec<u8> {
let mut d = Vec::new();
d.push(p.id);
d.push_all(p.payload.as_slice());
d
}
-
- // Data to be encrypted.
- let mut data =
+
+ // Data to be encrypted.
+ let mut data =
match self.t {
Command(ref p) | Answer(ref p) => packet_data(p),
Error(_) => Vec::from_elem(16, '0' as u8) // Padding as data: 16 * '0'.
};
-
+
// Compute the MAC
- let mac = crypto::compute_mac(data.as_slice());
-
+ let mac = crypto::compute_mac(data.as_slice());
+
// Padding.
match self.t {
Command(_) | Answer(_) => {
let padding_size = if data.len() % 16 == 0 { 16 } else { data.len() % 16 } ;
- data.push_all(Vec::from_elem(padding_size, padding_size as u8).as_slice());
+ data.reserve_additional(padding_size);
+ for i in range(0, padding_size) {
+ data.push(padd_fun(i, padding_size));
+ }
},
_ => ()
}
-
+
// Encrypt.
- let encrypted_data = crypto::encrypt(data.as_slice(), iv_from_timestamp(self.timestamp).as_slice());
-
+ let encrypted_data = crypto::encrypt(data.as_slice(), iv_from_timestamp(self.timestamp).as_slice());
+
// Write packet length.
try_write_io!(output.write_be_u16((encrypted_data.len() + FIXED_PACKET_SIZE) as u16));
-
+
// Write packet type.
try_write_io!(output.write_u8(
match self.t {
Command(_) => 0x00,
Answer(_) => 0xFF,
Error(CryptError) => 0x0A,
- Error(AuthError) => 0x0B
+ Error(AuthError) => 0x0B
}
));
-
+
// Write timestamp.
try_write_io!(output.write_be_u64(self.timestamp));
-
+
// Write encrypted data.
try_write_io!(output.write(encrypted_data.as_slice()));
-
+
// Write the MAC.
try_write_io!(output.write(mac));
-
+
Ok(())
}
-
+
pub fn read(input: &mut io::Reader) -> ReadingResult {
fn consume(input: &mut io::Reader, nb_byte: uint) {
- let _ = input.read_exact(nb_byte);
+ let _ = input.read_exact(nb_byte);
}
-
+
let data_size = try_read_io!(input.read_be_u16());
-
+
// Read and check the packet type.
- let packet_type = try_read_io!(input.read_u8());
+ let packet_type = try_read_io!(input.read_u8());
if ![0x00, 0xFF, 0x0A, 0x0B].iter().any(|p| *p == packet_type) {
consume(input, data_size as uint - 1);
return Err(UnknownPacketTypeError)
- }
-
+ }
+
let timestamp = try_read_io!(input.read_be_u64());
-
- let mut encrypted_data = Vec::from_elem(data_size as uint - FIXED_PACKET_SIZE, 0u8);
+
+ let mut encrypted_data = Vec::from_elem(data_size as uint - FIXED_PACKET_SIZE, 0u8);
if try_read_io!(input.read(encrypted_data.as_mut_slice_())) != encrypted_data.len() {
return Err(UnconsistentEncryptedSizeError)
}
let mut data = crypto::decrypt(encrypted_data.as_slice(), iv_from_timestamp(timestamp).as_slice());
-
- // Control the size and the content of the padding then remove it.
+
+ // Control the size and the content of the padding then remove it.
if packet_type == 0x00 || packet_type == 0xFF {
match data.last() {
- Some(&padding_size) => {
+ Some(&padding_size) => {
if padding_size as uint > data.len() || !data.slice_from(data.len() - padding_size as uint).iter().any(|b| *b == padding_size) {
+ consume(input, 10);
return Err(PaddingError)
}
let data_length = data.len() - padding_size as uint;
return Err(PaddingError)
}
}
-
+
// Read an verify the MAC.
let mut mac_read = [0u8, ..10];
if try_read_io!(input.read(mac_read)) != mac_read.len() {
if mac_read != mac_data {
return Err(MACMismatchError)
}
-
+
Ok(Packet {
t: match packet_type {
// Command or answer.
match packet_type { 0x00 => Command(pd), _ => Answer(pd) }
},
// Error.
- _ => {
+ _ => {
if data.len() != 16 {
return Err(UnconsistentDataSizeError)
- } else if data != Vec::from_elem(16, '0' as u8) {
+ } else if data != Vec::from_elem(16, '0' as u8) {
return Err(DataError)
}
- match packet_type { 0x0A => Error(CryptError), _ => Error(AuthError) }
+ match packet_type { 0x0A => Error(CryptError), _ => Error(AuthError) }
}
},
timestamp: timestamp