Add config to mark server as read-only

This commit is contained in:
Foorack / Max Faxälv 2023-07-16 17:26:59 +02:00 committed by Altuğ Bakan
parent b14d066d5a
commit 38e6ad3360
3 changed files with 29 additions and 3 deletions

View file

@ -26,10 +26,10 @@ cargo install tftpd
tftpd --help tftpd --help
``` ```
To run the server on the IP address `0.0.0.0`, port `1234` in the `/home/user/tftp` directory: To run the server on the IP address `0.0.0.0`, read-only, on port `1234` in the `/home/user/tftp` directory:
```bash ```bash
tftpd -i 0.0.0.0 -p 1234 -d "/home/user/tftp" tftpd -i 0.0.0.0 -p 1234 -d "/home/user/tftp" --read-only
``` ```
## License ## License

View file

@ -27,6 +27,8 @@ pub struct Config {
pub directory: PathBuf, pub directory: PathBuf,
/// Use a single port for both sending and receiving. (default: false) /// Use a single port for both sending and receiving. (default: false)
pub single_port: bool, pub single_port: bool,
/// Refuse all write requests, making the server read-only. (default: false)
pub read_only: bool,
} }
impl Config { impl Config {
@ -38,6 +40,7 @@ impl Config {
port: 69, port: 69,
directory: env::current_dir().unwrap_or_else(|_| env::temp_dir()), directory: env::current_dir().unwrap_or_else(|_| env::temp_dir()),
single_port: false, single_port: false,
read_only: false,
}; };
args.next(); args.next();
@ -71,6 +74,9 @@ impl Config {
"-s" | "--single-port" => { "-s" | "--single-port" => {
config.single_port = true; config.single_port = true;
} }
"-r" | "--read-only" => {
config.read_only = true;
}
"-h" | "--help" => { "-h" | "--help" => {
println!("TFTP Server Daemon\n"); println!("TFTP Server Daemon\n");
println!("Usage: tftpd [OPTIONS]\n"); println!("Usage: tftpd [OPTIONS]\n");
@ -81,6 +87,7 @@ impl Config {
); );
println!(" -d, --directory <DIRECTORY>\tSet the listening port of the server (default: Current Working Directory)"); println!(" -d, --directory <DIRECTORY>\tSet the listening port of the server (default: Current Working Directory)");
println!(" -s, --single-port\t\tUse a single port for both sending and receiving (default: false)"); println!(" -s, --single-port\t\tUse a single port for both sending and receiving (default: false)");
println!(" -r, --read-only\t\tRefuse all write requests, making the server read-only (default: false)");
println!(" -h, --help\t\t\tPrint help information"); println!(" -h, --help\t\t\tPrint help information");
process::exit(0); process::exit(0);
} }
@ -101,7 +108,7 @@ mod tests {
#[test] #[test]
fn parses_full_config() { fn parses_full_config() {
let config = Config::new( let config = Config::new(
vec!["/", "-i", "0.0.0.0", "-p", "1234", "-d", "/", "-s"] vec!["/", "-i", "0.0.0.0", "-p", "1234", "-d", "/", "-s", "-r"]
.iter() .iter()
.map(|s| s.to_string()), .map(|s| s.to_string()),
) )
@ -111,6 +118,7 @@ mod tests {
assert_eq!(config.port, 1234); assert_eq!(config.port, 1234);
assert_eq!(config.directory, PathBuf::from_str("/").unwrap()); assert_eq!(config.directory, PathBuf::from_str("/").unwrap());
assert!(config.single_port); assert!(config.single_port);
assert!(config.read_only);
} }
#[test] #[test]

View file

@ -31,6 +31,7 @@ pub struct Server {
socket: UdpSocket, socket: UdpSocket,
directory: PathBuf, directory: PathBuf,
single_port: bool, single_port: bool,
read_only: bool,
largest_block_size: usize, largest_block_size: usize,
clients: HashMap<SocketAddr, Sender<Packet>>, clients: HashMap<SocketAddr, Sender<Packet>>,
} }
@ -44,6 +45,7 @@ impl Server {
socket, socket,
directory: config.directory.clone(), directory: config.directory.clone(),
single_port: config.single_port, single_port: config.single_port,
read_only: config.read_only,
largest_block_size: DEFAULT_BLOCK_SIZE, largest_block_size: DEFAULT_BLOCK_SIZE,
clients: HashMap::new(), clients: HashMap::new(),
}; };
@ -77,6 +79,22 @@ impl Server {
mut options, mut options,
.. ..
} => { } => {
if self.read_only {
if Socket::send_to(
&self.socket,
&Packet::Error {
code: ErrorCode::AccessViolation,
msg: "server is read-only".to_string(),
},
&from,
)
.is_err()
{
eprintln!("Could not send error packet");
};
eprintln!("Received invalid request");
continue;
}
println!("Receiving {filename} from {from}"); println!("Receiving {filename} from {from}");
if let Err(err) = self.handle_wrq(filename.clone(), &mut options, &from) { if let Err(err) = self.handle_wrq(filename.clone(), &mut options, &from) {
eprintln!("Error while receiving file: {err}") eprintln!("Error while receiving file: {err}")