Add work on windowsize and run clippy
This commit is contained in:
parent
9e83591bae
commit
361d077d1b
8 changed files with 106 additions and 53 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -4,4 +4,4 @@ version = 3
|
|||
|
||||
[[package]]
|
||||
name = "tftpd"
|
||||
version = "0.1.5"
|
||||
version = "0.1.6"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
43
src/window.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
|
|
@ -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")?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue