Add work on windowsize and run clippy

This commit is contained in:
altugbakan 2023-03-29 20:07:42 +03:00 committed by Altuğ Bakan
parent 9e83591bae
commit 361d077d1b
8 changed files with 106 additions and 53 deletions

2
Cargo.lock generated
View file

@ -4,4 +4,4 @@ version = 3
[[package]]
name = "tftpd"
version = "0.1.5"
version = "0.1.6"

View file

@ -1,6 +1,6 @@
[package]
name = "tftpd"
version = "0.1.5"
version = "0.1.6"
authors = ["Altuğ Bakan <mail@alt.ug>"]
edition = "2021"
description = "Multithreaded TFTP server daemon"

View file

@ -7,6 +7,7 @@ This server implements [RFC 1350](https://www.rfc-editor.org/rfc/rfc1350), The T
- [RFC 2348](https://www.rfc-editor.org/rfc/rfc2348) Blocksize Option
- [RFC 2349](https://www.rfc-editor.org/rfc/rfc2349) Timeout Interval Option
- [RFC 2349](https://www.rfc-editor.org/rfc/rfc2349) Transfer Size Option
- [RFC 7440](https://www.rfc-editor.org/rfc/rfc7440) Windowsize Option
# Security

View file

@ -8,6 +8,7 @@
//! - [RFC 2348](https://www.rfc-editor.org/rfc/rfc2348) Blocksize Option
//! - [RFC 2349](https://www.rfc-editor.org/rfc/rfc2349) Timeout Interval Option
//! - [RFC 2349](https://www.rfc-editor.org/rfc/rfc2349) Transfer Size Option
//! - [RFC 7440](https://www.rfc-editor.org/rfc/rfc7440) Windowsize Option
//!
//! # Security
//!
@ -19,6 +20,7 @@ mod convert;
mod message;
mod packet;
mod server;
mod window;
mod worker;
pub use config::Config;
@ -30,4 +32,5 @@ pub use packet::OptionType;
pub use packet::Packet;
pub use packet::TransferOption;
pub use server::Server;
pub use window::Window;
pub use worker::Worker;

View file

@ -1,5 +1,5 @@
use crate::Convert;
use std::{error::Error, fmt};
use std::{error::Error, fmt, str::FromStr};
/// Packet `enum` represents the valid TFTP packet types.
///
@ -127,7 +127,7 @@ impl Opcode {
/// Converts a [`u16`] to a [`u8`] array with 2 elements.
pub const fn as_bytes(self) -> [u8; 2] {
return (self as u16).to_be_bytes();
(self as u16).to_be_bytes()
}
}
@ -199,14 +199,18 @@ impl OptionType {
OptionType::Timeout => "timeout",
}
}
}
impl FromStr for OptionType {
type Err = &'static str;
/// Converts a [`str`] to an [`OptionType`].
pub fn from_str(value: &str) -> Result<Self, &'static str> {
fn from_str(value: &str) -> Result<Self, &'static str> {
match value {
"blksize" => Ok(OptionType::BlockSize),
"tsize" => Ok(OptionType::TransferSize),
"timeout" => Ok(OptionType::Timeout),
_ => Err("Invalid option type".into()),
_ => Err("Invalid option type"),
}
}
}
@ -263,7 +267,7 @@ impl ErrorCode {
/// Converts an [`ErrorCode`] to a [`u8`] array with 2 elements.
pub fn as_bytes(self) -> [u8; 2] {
return (self as u16).to_be_bytes();
(self as u16).to_be_bytes()
}
}
@ -360,7 +364,7 @@ fn serialize_error(code: &ErrorCode, msg: &String) -> Vec<u8> {
[
&Opcode::Error.as_bytes()[..],
&code.as_bytes()[..],
&msg.as_bytes()[..],
msg.as_bytes(),
&[0x00],
]
.concat()
@ -384,9 +388,9 @@ mod tests {
fn parses_read_request() {
let buf = [
&Opcode::Rrq.as_bytes()[..],
&"test.png".as_bytes(),
("test.png".as_bytes()),
&[0x00],
&"octet".as_bytes(),
("octet".as_bytes()),
&[0x00],
]
.concat();
@ -409,17 +413,17 @@ mod tests {
fn parses_read_request_with_options() {
let buf = [
&Opcode::Rrq.as_bytes()[..],
&"test.png".as_bytes(),
("test.png".as_bytes()),
&[0x00],
&"octet".as_bytes(),
("octet".as_bytes()),
&[0x00],
&OptionType::TransferSize.as_str().as_bytes(),
(OptionType::TransferSize.as_str().as_bytes()),
&[0x00],
&"0".as_bytes(),
("0".as_bytes()),
&[0x00],
&OptionType::Timeout.as_str().as_bytes(),
(OptionType::Timeout.as_str().as_bytes()),
&[0x00],
&"5".as_bytes(),
("5".as_bytes()),
&[0x00],
]
.concat();
@ -456,9 +460,9 @@ mod tests {
fn parses_write_request() {
let buf = [
&Opcode::Wrq.as_bytes()[..],
&"test.png".as_bytes(),
("test.png".as_bytes()),
&[0x00],
&"octet".as_bytes(),
("octet".as_bytes()),
&[0x00],
]
.concat();
@ -481,17 +485,17 @@ mod tests {
fn parses_write_request_with_options() {
let buf = [
&Opcode::Wrq.as_bytes()[..],
&"test.png".as_bytes(),
("test.png".as_bytes()),
&[0x00],
&"octet".as_bytes(),
("octet".as_bytes()),
&[0x00],
&OptionType::TransferSize.as_str().as_bytes(),
(OptionType::TransferSize.as_str().as_bytes()),
&[0x00],
&"12341234".as_bytes(),
("12341234".as_bytes()),
&[0x00],
&OptionType::BlockSize.as_str().as_bytes(),
(OptionType::BlockSize.as_str().as_bytes()),
&[0x00],
&"1024".as_bytes(),
("1024".as_bytes()),
&[0x00],
]
.concat();

View file

@ -2,7 +2,7 @@ use crate::{Config, Message, Worker};
use crate::{ErrorCode, Packet, TransferOption};
use std::error::Error;
use std::net::{SocketAddr, UdpSocket};
use std::path::PathBuf;
use std::path::{Path, PathBuf};
/// Server `struct` is used for handling incoming TFTP requests.
///
@ -79,11 +79,11 @@ impl Server {
fn handle_rrq(
&self,
filename: String,
options: &mut Vec<TransferOption>,
options: &mut [TransferOption],
to: &SocketAddr,
) -> Result<(), Box<dyn Error>> {
let file_path = &self.directory.join(&filename);
match check_file_exists(&file_path, &self.directory) {
let file_path = &self.directory.join(filename);
match check_file_exists(file_path, &self.directory) {
ErrorCode::FileNotFound => Message::send_error_to(
&self.socket,
to,
@ -96,12 +96,15 @@ impl Server {
ErrorCode::AccessViolation,
"file access violation",
),
ErrorCode::FileExists => Ok(Worker::send(
self.socket.local_addr()?,
*to,
file_path.to_path_buf(),
options.to_vec(),
)),
ErrorCode::FileExists => {
Worker::send(
self.socket.local_addr()?,
*to,
file_path.to_path_buf(),
options.to_vec(),
);
Ok(())
}
_ => Err("unexpected error code when checking file".into()),
}
}
@ -109,11 +112,11 @@ impl Server {
fn handle_wrq(
&self,
filename: String,
options: &mut Vec<TransferOption>,
options: &mut [TransferOption],
to: &SocketAddr,
) -> Result<(), Box<dyn Error>> {
let file_path = &self.directory.join(&filename);
match check_file_exists(&file_path, &self.directory) {
let file_path = &self.directory.join(filename);
match check_file_exists(file_path, &self.directory) {
ErrorCode::FileExists => Message::send_error_to(
&self.socket,
to,
@ -126,18 +129,21 @@ impl Server {
ErrorCode::AccessViolation,
"file access violation",
),
ErrorCode::FileNotFound => Ok(Worker::receive(
self.socket.local_addr()?,
*to,
file_path.to_path_buf(),
options.to_vec(),
)),
ErrorCode::FileNotFound => {
Worker::receive(
self.socket.local_addr()?,
*to,
file_path.to_path_buf(),
options.to_vec(),
);
Ok(())
}
_ => Err("unexpected error code when checking file".into()),
}
}
}
fn check_file_exists(file: &PathBuf, directory: &PathBuf) -> ErrorCode {
fn check_file_exists(file: &Path, directory: &PathBuf) -> ErrorCode {
if !validate_file_path(file, directory) {
return ErrorCode::AccessViolation;
}
@ -149,7 +155,7 @@ fn check_file_exists(file: &PathBuf, directory: &PathBuf) -> ErrorCode {
ErrorCode::FileExists
}
fn validate_file_path(file: &PathBuf, directory: &PathBuf) -> bool {
fn validate_file_path(file: &Path, directory: &PathBuf) -> bool {
!file.to_str().unwrap().contains("..") && file.ancestors().any(|a| a == directory)
}

43
src/window.rs Normal file
View file

@ -0,0 +1,43 @@
use std::{collections::VecDeque, error::Error, fs::File, io::Read};
pub struct Window {
elements: VecDeque<Vec<u8>>,
size: usize,
chunk_size: usize,
file: File,
}
impl Window {
pub fn new(size: usize, chunk_size: usize, file: File) -> Window {
Window {
elements: VecDeque::new(),
size,
chunk_size,
file,
}
}
pub fn fill(&mut self) -> Result<(), Box<dyn Error>> {
for _ in self.elements.len()..self.size {
let mut chunk = vec![0; self.chunk_size];
let size = self.file.read(&mut chunk)?;
self.elements.push_back(chunk);
if size != self.chunk_size {
break;
}
}
Ok(())
}
pub fn remove(&mut self, amount: usize) -> Result<(), Box<dyn Error>> {
if amount > self.elements.len() {
return Err("amount cannot be larger than size".into());
}
drop(self.elements.drain(0..amount));
Ok(())
}
}

View file

@ -180,7 +180,7 @@ fn receive_file(
}) => {
if received_block_number == block_number.wrapping_add(1) {
block_number = received_block_number;
file.write(&data)?;
file.write_all(&data)?;
size = data.len();
break;
}
@ -216,7 +216,7 @@ fn accept_request(
options: &Vec<TransferOption>,
work_type: &WorkType,
) -> Result<(), Box<dyn Error>> {
if options.len() > 0 {
if !options.is_empty() {
Message::send_oack(socket, options.to_vec())?;
} else if *work_type == WorkType::Receive {
Message::send_ack(socket, 0)?
@ -226,13 +226,9 @@ fn accept_request(
}
fn check_response(socket: &UdpSocket) -> Result<(), Box<dyn Error>> {
if let Packet::Ack(received_block_number) = Message::recv(&socket)? {
if let Packet::Ack(received_block_number) = Message::recv(socket)? {
if received_block_number != 0 {
Message::send_error(
&socket,
ErrorCode::IllegalOperation,
"invalid oack response",
)?;
Message::send_error(socket, ErrorCode::IllegalOperation, "invalid oack response")?;
}
}