class TFTP::Handler::RWSimple
Basic read-write session over a 'physical' directory.
Public Class Methods
new(path, opts = {})
click to toggle source
Initialize the handler.
Options:
- :no_read => deny read access if true - :no_write => deny write access if true
@param path [String] Path to serving root directory @param opts [Hash] Options
Calls superclass method
TFTP::Handler::Base::new
# File lib/tftp/tftp.rb, line 212 def initialize(path, opts = {}) @path = path super(opts) end
Public Instance Methods
run!(tag, req, sock, src)
click to toggle source
Handle a session.
Has to close the socket (and any other resources). Note that the current version 'guards' against path traversal by a simple substitution of '..' with '__'.
@param tag [String] Tag used for logging @param req [Packet] The initial request packet @param sock [UDPSocket] Connected socket @param src [UDPSource] Initial connection information
# File lib/tftp/tftp.rb, line 227 def run!(tag, req, sock, src) name = req.filename.gsub('..', '__') path = File.join(@path, name) case req when Packet::RRQ if @opts[:no_read] log :info, "#{tag} Denied read request for #{req.filename}" sock.send(Packet::ERROR.new(2, 'Access denied.').encode, 0) sock.close return end log :info, "#{tag} Read request for #{req.filename} (#{req.mode})" unless File.exist? path log :warn, "#{tag} File not found" sock.send(Packet::ERROR.new(1, 'File not found.').encode, 0) sock.close return end mode = 'r' mode += 'b' if req.mode == :octet io = File.open(path, mode) send(tag, sock, io) sock.close io.close when Packet::WRQ if @opts[:no_write] log :info, "#{tag} Denied write request for #{req.filename}" sock.send(Packet::ERROR.new(2, 'Access denied.').encode, 0) sock.close return end log :info, "#{tag} Write request for #{req.filename} (#{req.mode})" mode = 'w' mode += 'b' if req.mode == :octet io = File.open(path, mode) ok = recv(tag, sock, io) sock.close io.close unless ok log :warn, "#{tag} Removing partial file #{req.filename}" File.delete(path) end end end