allenap_libtftp/lib.rs
1#[macro_use]
2extern crate slog;
3
4use std::io;
5use std::net;
6use std::error::Error;
7
8pub mod options;
9pub mod packet;
10mod packetreader;
11mod packetwriter;
12pub mod rrq;
13
14use self::options::Options;
15use self::packet::{Filename, Packet, TransferMode};
16
17
18/// Starts a TFTP server at the given address.
19///
20/// Well-formed requests are passed to `handler`, and all logging is
21/// handled by `logger`.
22pub fn serve(
23 addr: net::SocketAddr, handler: &Handler, logger: &slog::Logger)
24 -> io::Result<()>
25{
26 let socket = net::UdpSocket::bind(addr)?;
27 info!(logger, "Listening"; "address" => format!("{}", addr));
28
29 // RFC-2347 says "The maximum size of a request packet is 512 octets."
30 let mut bufin = [0; 512];
31 let mut bufout = [0; 4 + 512];
32 loop {
33 match socket.recv_from(&mut bufin) {
34 Ok((size, src)) => {
35 match Packet::parse(&mut bufin[..size]) {
36 Ok(packet) => {
37 match handler.handle(addr, src, packet) {
38 Some(packet) => {
39 let size = packet.write(&mut bufout)?;
40 socket.send_to(&bufout[..size], &src)?;
41 },
42 None => {},
43 };
44 },
45 Err(error) => warn!(
46 logger, "Ignoring malformed packet";
47 "error" => error.description()),
48 }
49 },
50 Err(error) => return Err(error),
51 }
52 };
53}
54
55
56/// A TFTP handler to which requests are passed once they've been
57/// parsed. A handler can choose to ignore, reject (with an error), or
58/// serve each request that comes in.
59pub trait Handler {
60
61 /// Handle a new, well-formed, TFTP request.
62 ///
63 /// The default implementation calls
64 /// [`handle_rrq`](#method.handle_rrq) for a read request and
65 /// [`handle_wrq`](#method.handle_wrq) for a write request, and
66 /// [`handle_other`](#method.handle_other) for everything else.
67 ///
68 /// In case of an error, this can return a `Packet` representing the
69 /// error to be sent to the other side. For example:
70 ///
71 /// ```
72 /// # use allenap_libtftp::packet;
73 /// Some(packet::Packet::Error(
74 /// packet::ErrorCode::AccessViolation,
75 /// packet::ErrorMessage("read not supported".to_owned()),
76 /// ));
77 /// ```
78 ///
79 /// Use this when the error occurs prior the commencing the
80 /// transfer; once the transfer has begin, send errors via the
81 /// channel created for the transfer.
82 fn handle(
83 &self, local: net::SocketAddr, remote: net::SocketAddr, packet: Packet)
84 -> Option<Packet>
85 {
86 match packet {
87 Packet::Read(filename, txmode, options) =>
88 self.handle_rrq(local, remote, filename, txmode, options),
89 Packet::Write(filename, txmode, options) =>
90 self.handle_wrq(local, remote, filename, txmode, options),
91 packet =>
92 self.handle_other(local, remote, packet),
93 }
94 }
95
96 /// Handle a read request (`RRQ`).
97 ///
98 /// By default this is rejected as an access violation. Implementors
99 /// can define something more interesting.
100 fn handle_rrq(
101 &self, _local: net::SocketAddr, _remote: net::SocketAddr,
102 _filename: Filename, _txmode: TransferMode, _options: Options)
103 -> Option<Packet>
104 {
105 Some(Packet::Error(
106 packet::ErrorCode::AccessViolation,
107 packet::ErrorMessage("read not supported".to_owned()),
108 ))
109 }
110
111 /// Handle a write request (`WRQ`).
112 ///
113 /// By default this is rejected as an access violation. Implementors
114 /// can define something more interesting.
115 fn handle_wrq(
116 &self, _local: net::SocketAddr, _remote: net::SocketAddr,
117 _filename: Filename, _txmode: TransferMode, _options: Options)
118 -> Option<Packet>
119 {
120 Some(Packet::Error(
121 packet::ErrorCode::AccessViolation,
122 packet::ErrorMessage("write not supported".to_owned()),
123 ))
124 }
125
126 /// Handle all other requests.
127 ///
128 /// By default these are completely ignored. The TFTP specs do not
129 /// define request types other than `RRQ` and `WRQ` so this might be
130 /// a misdirected or corrupted packet. Implementors may want to log
131 /// this.
132 fn handle_other(
133 &self, _local: net::SocketAddr, _remote: net::SocketAddr,
134 _packet: Packet)
135 -> Option<Packet>
136 {
137 None // Ignore.
138 }
139
140}
141
142
143/// Bind a new UDP socket at the given address.
144fn make_socket(peer: net::SocketAddr) -> io::Result<net::UdpSocket> {
145 match peer {
146 net::SocketAddr::V4(_) => net::UdpSocket::bind(("0.0.0.0", 0)),
147 net::SocketAddr::V6(_) => net::UdpSocket::bind(("::", 0)),
148 }
149}