fx-tftp 0.7 → 1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2fb93e7d9a4839d3065a2ac891b2e9a9960631a9
4
- data.tar.gz: 5bd896cb10fb366ff12062e469910ec923769b88
3
+ metadata.gz: 2eb12234e670c55c0c634f86118f62d56ca172a7
4
+ data.tar.gz: 9e02a93b38f29149e36c3294c751c78581675f13
5
5
  SHA512:
6
- metadata.gz: d53e82bcbac0ef1765d7f350ad8946a066a5d264214a97d47b6c126417f08579bef6902eb29f74159c946d164cd902fe09090928da7ace928dc89866ef3ae9d7
7
- data.tar.gz: 35263c555fe01030069daccf62283de35ab72f13e92f14aff5ed934e6d22b55d339ffd520470b48360445dce6d8c7a1928a6d1adc2136e86a34adb2c7190075b
6
+ metadata.gz: 1b2de98e63190ff5fca124b8a4e47fa90ac5a2247ad0e6d506a6457bee3cc0c1f646ed9a003d40fc8d437e2dec2cb14fe71c21e1ff1b883431d01f40c8f7fa29
7
+ data.tar.gz: b8654091eceed1f70276b2f090e5e228634ab22af969844f6820c58b1cde12e4a60c65e76fa8a22e97e074b647a16d7366c1b28eb8298806cec1c962bb485156
data/.gitignore CHANGED
@@ -1,4 +1,11 @@
1
- doc/
2
- pkg/
3
- .yardoc/
4
- Gemfile.lock
1
+ /.bundle/
2
+ /vendor/
3
+ /.ruby-version
4
+ /.yardoc
5
+ /Gemfile.lock
6
+ /_yardoc/
7
+ /coverage/
8
+ /doc/
9
+ /pkg/
10
+ /spec/reports/
11
+ /tmp/
@@ -1,8 +1,9 @@
1
1
  language: ruby
2
2
  rvm:
3
- - ruby-head
3
+ - 2.2.3
4
+ - 2.1.7
5
+ - 2.0.0
4
6
  - 1.9.3
5
- install:
6
- - gem install minitest
7
+ before_install: gem install bundler -v 1.10.6
7
8
  script:
8
9
  - rake test
data/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  * [Homepage](https://github.com/drbig/fx-tftp)
4
4
  * [Documentation](http://rubydoc.info/gems/fx-tftp/frames)
5
5
 
6
+
6
7
  ## Description
7
8
 
8
9
  FX-TFTP is a slightly over-OO-ed pure-Ruby implementation of plain [RFC1350](https://www.ietf.org/rfc/rfc1350.txt) TFTP *server*. It is very flexible and intended for hacking. Also, and more importantly, it **works**, contrary to other gems that are occupying space at RubyGems.
@@ -11,6 +12,28 @@ That flexibility may be useful if you're planning on massive custom TFTP-based b
11
12
 
12
13
  The included `tftpd` executable gives you a fully-fledged read-write TFTP server that also does logging, daemon mode and does not crap out on `SIGTERM`.
13
14
 
15
+
16
+ ## Quickstart
17
+
18
+ Just in case you need an easy to use tftp server...
19
+ Install via Rubygems:
20
+
21
+ $ gem install fx-tftp
22
+
23
+ Then start the beast with any directory you want to serve (works for uploads and downloads as well):
24
+
25
+ $ sudo tftpd ~/router_firmwares_and_config_files/
26
+
27
+ Further options:
28
+
29
+ $ tftpd
30
+ Usage: tftpd [OPTIONS] DIR
31
+ -V, --version Show version and exit
32
+ -a, --address ADDRESS Address to listen on (default: 0.0.0.0)
33
+ -p, --port PORT Port to listen on (default: 69)
34
+ -v, --verbose Enable verbose output
35
+
36
+
14
37
  ## Hacking
15
38
 
16
39
  Suppose we want to have a TFTP server that only supports reading, but the files served should depend on the IP block the client is connecting from:
@@ -28,18 +51,6 @@ Suppose we want to have a TFTP server that only supports reading, but the files
28
51
 
29
52
  When you combine filename inspection and `#send` and `#recv` methods working on plain `IO` objects you can easily whip up things like serving dynamically built scripts/binaries/archives based on parameters passed as the requested 'filename'.
30
53
 
31
- ## Included executable
32
-
33
- $ tftpd
34
- Usage: tftpd [OPTIONS] PORT
35
- -v, --version Show version and exit
36
- -d, --debug Enable debug output
37
- -l, --log PATH Log to file
38
- -b, --background Fork into background
39
- -m, --mode MODE Run in R/W only mode
40
- -h, --host HOST Bind do host
41
- -p, --path PATH Serving root directory
42
- -o, --overwrite Overwrite existing files
43
54
 
44
55
  ## Contributing
45
56
 
@@ -50,6 +61,7 @@ Fell free to contributed patches using the common GitHub model (descried below).
50
61
  - Write code and tests, check, commit
51
62
  - Make a Pull Request
52
63
 
64
+
53
65
  ## Licensing
54
66
 
55
67
  Standard two-clause BSD license, see LICENSE.txt for details.
data/bin/tftpd CHANGED
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
- #
3
2
 
4
3
  $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
5
4
 
@@ -7,59 +6,42 @@ require 'logger'
7
6
  require 'optparse'
8
7
  require 'tftp'
9
8
 
10
- config = {:path => Dir.pwd, :host => '127.0.0.1', :fork => false,
11
- :ver => false, :loglevel => Logger::INFO, :logfile => STDOUT,
12
- :no_read => false, :no_write => false, :overwrite => false}
13
-
14
- def die!(msg)
15
- STDERR.puts msg
16
- exit(2)
17
- end
9
+ # Defaults
10
+ config = { :port => 69, :address => '0.0.0.0', :loglevel => Logger::WARN }
18
11
 
19
12
  op = OptionParser.new do |o|
20
- o.banner = "Usage: #{$PROGRAM_NAME} [OPTIONS] PORT"
21
- o.on('-v', '--version', 'Show version and exit') { config[:ver] = true }
22
- o.on('-d', '--debug', 'Enable debug output') { config[:loglevel] = Logger::DEBUG }
23
- o.on('-l', '--log PATH', String, 'Log to file') {|a| config[:logfile] = a }
24
- o.on('-b', '--background', 'Fork into background') {|a| config[:fork] = true }
25
- o.on('-m', '--mode MODE', String, 'Run in R/W only mode') do |a|
26
- case a.downcase[0]
27
- when 'r'
28
- config[:no_write] = true
29
- when 'w'
30
- config[:no_read] = true
31
- else
32
- config[:bad_mode] = true
33
- end
13
+ o.banner = "Usage: #{$PROGRAM_NAME} [OPTIONS] DIR"
14
+ o.on '-V', '--version', 'Show version and exit' do
15
+ puts "fx-tftpd v#{TFTP::VERSION} Copyright (c) 2015, Piotr S. Staszewski"
16
+ exit
17
+ end
18
+ o.on '-a', '--address ADDRESS', String,
19
+ 'Address to listen on (default: 0.0.0.0)' do |address|
20
+ config[:address] = address
21
+ end
22
+ o.on '-p', '--port PORT', Integer,
23
+ 'Port to listen on (default: 69)' do |port|
24
+ abort 'Invalid port' if port < 1 || port > 65535
25
+ config[:port] = port
26
+ end
27
+ o.on '-v', '--verbose', 'Enable verbose output' do
28
+ config[:loglevel] = Logger::INFO
34
29
  end
35
- o.on('-h', '--host HOST', String, 'Bind do host') {|a| config[:host] = a }
36
- o.on('-p', '--path PATH', String, 'Serving root directory') {|a| config[:path] = a }
37
- o.on('-o', '--overwrite', 'Overwrite existing files') { config[:overwrite] = true }
38
- end
39
- op.parse! or die!(op)
40
- die!(op) if config[:bad_mode]
41
-
42
- if config[:ver]
43
- puts "fx-tftpd v#{TFTP::VERSION} Copyright (c) 2015, Piotr S. Staszewski"
44
- exit
45
30
  end
46
31
 
47
- die!('Serving root does not exists') unless File.exists? config[:path]
32
+ config[:path] = op.parse!.first
33
+ abort 'Last argument must be a directory' unless File.directory? config[:path]
48
34
 
49
- PORT = ARGV.shift.to_i
50
- die!(op) if PORT < 1 || PORT > 65535
35
+ if config[:port] < 1024 && !Process.euid.zero?
36
+ abort 'Please run tftpd as root via sudo!'
37
+ end
51
38
 
52
- log = Logger.new(config[:logfile])
39
+ log = Logger.new(STDOUT)
53
40
  log.level = config[:loglevel]
54
- log.formatter = lambda {|s, d, p, m| "#{d.strftime('%Y-%m-%d %H:%M:%S.%3N')} | #{s.ljust(5)} | #{m}\n" }
55
-
56
- if config[:fork]
57
- log.info 'Detaching from the console'
58
- Process.daemon(true)
41
+ log.formatter = lambda do |s, d, p, m|
42
+ "#{d.strftime('%Y-%m-%d %H:%M:%S.%3N')} | #{s.ljust(5)} | #{m}\n"
59
43
  end
60
-
61
44
  config[:logger] = log
62
- config[:port] = PORT
63
45
 
64
46
  begin
65
47
  log.info "Serving from and to #{config[:path]}"
@@ -255,16 +255,6 @@ module TFTP
255
255
  return
256
256
  end
257
257
  log :info, "#{tag} Write request for #{req.filename} (#{req.mode})"
258
- if File.exist? path
259
- if @opts[:overwrite]
260
- log :info, "#{tag} Overwrite existing file #{req.filename}"
261
- else
262
- log :warn, "#{tag} Refuse to overwrite existing file #{req.filename}"
263
- sock.send(Packet::ERROR.new(6, 'File already exists.').encode, 0)
264
- sock.close
265
- return
266
- end
267
- end
268
258
  mode = 'w'
269
259
  mode += 'b' if req.mode == :octet
270
260
  io = File.open(path, mode)
@@ -288,28 +278,28 @@ module TFTP
288
278
  # test it for 10K or something.
289
279
  #
290
280
  # @attr handler [Handler] Session handler
291
- # @attr host [String] Host the sockets bind to
281
+ # @attr address [String] Address to listen to
292
282
  # @attr port [Integer] Session dispatcher port
293
283
  # @attr clients [Hash] Current sessions
294
284
  class Base
295
- attr_reader :handler, :host, :port, :clients
285
+ attr_reader :handler, :address, :port, :clients
296
286
 
297
287
  # Initialize the server.
298
288
  #
299
289
  # Options:
300
290
  #
301
- # - :host => host to bind to (default: 127.0.0.1)
302
- # - :port => dispatcher port (default: 69)
303
- # - :logger => logger instance
291
+ # - :address => address to listen to (default: '0.0.0.0')
292
+ # - :port => dispatcher port (default: 69)
293
+ # - :logger => logger instance
304
294
  #
305
295
  # @param handler [Handler] Initialized session handler
306
296
  # @param opts [Hash] Options
307
297
  def initialize(handler, opts = {})
308
298
  @handler = handler
309
299
 
310
- @host = opts[:host] || '127.0.0.1'
311
- @port = opts[:port] || 69
312
- @logger = opts[:logger]
300
+ @address = opts[:address] || '0.0.0.0'
301
+ @port = opts[:port] || 69
302
+ @logger = opts[:logger]
313
303
 
314
304
  @clients = Hash.new
315
305
  @run = false
@@ -319,9 +309,9 @@ module TFTP
319
309
  #
320
310
  # This is obviously blocking.
321
311
  def run!
322
- log :info, "UDP server loop at #{@host}:#{@port}"
312
+ log :info, "UDP server loop at #{@address}:#{@port}"
323
313
  @run = true
324
- Socket.udp_server_loop(@host, @port) do |msg, src|
314
+ Socket.udp_server_loop(@address, @port) do |msg, src|
325
315
  break unless @run
326
316
 
327
317
  addr = src.remote_address
@@ -338,7 +328,7 @@ module TFTP
338
328
  log :debug, "#{tag} -> PKT: #{pkt.inspect}"
339
329
  tid = get_tid
340
330
  tag = "[#{addr.ip_address}:#{addr.ip_port.to_s.ljust(5)}:#{tid.to_s.ljust(5)}]"
341
- sock = addr.connect_from(@host, tid)
331
+ sock = addr.connect_from(@address, tid)
342
332
  @clients[tid] = tag
343
333
 
344
334
  unless pkt.is_a?(Packet::RRQ) || pkt.is_a?(Packet::WRQ)
@@ -363,7 +353,7 @@ module TFTP
363
353
  def stop
364
354
  log :info, 'Stopping UDP server loop'
365
355
  @run = false
366
- UDPSocket.new.send('break', 0, @host, @port)
356
+ UDPSocket.new.send('break', 0, @address, @port)
367
357
  end
368
358
 
369
359
  private
@@ -1,4 +1,4 @@
1
1
  module TFTP
2
2
  # Current version string.
3
- VERSION = '0.7'
3
+ VERSION = '1.0'
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fx-tftp
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.7'
4
+ version: '1.0'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr S. Staszewski
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-11-19 00:00:00.000000000 Z
11
+ date: 2015-12-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubygems-tasks