fx-tftp 0.7 → 1.0

Sign up to get free protection for your applications and to get access to all the features.
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