ftpd 1.1.1 → 2.0.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.
Files changed (156) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/Changelog.md +15 -0
  4. data/Gemfile +2 -2
  5. data/Gemfile.lock +57 -48
  6. data/README.md +8 -1
  7. data/VERSION +1 -1
  8. data/examples/example.rb +12 -0
  9. data/features/example/step_definitions/example_server.rb +2 -0
  10. data/features/ftp_server/eprt.feature +1 -0
  11. data/features/ftp_server/epsv.feature +1 -0
  12. data/features/ftp_server/get_ipv6.feature +3 -0
  13. data/features/ftp_server/pasv.feature +10 -3
  14. data/features/ftp_server/step_definitions/logging.rb +2 -0
  15. data/features/ftp_server/step_definitions/test_server.rb +6 -0
  16. data/features/step_definitions/append.rb +2 -0
  17. data/features/step_definitions/client.rb +3 -0
  18. data/features/step_definitions/client_and_server_files.rb +2 -0
  19. data/features/step_definitions/client_files.rb +2 -0
  20. data/features/step_definitions/command.rb +2 -0
  21. data/features/step_definitions/connect.rb +2 -0
  22. data/features/step_definitions/delete.rb +2 -0
  23. data/features/step_definitions/directory_navigation.rb +2 -0
  24. data/features/step_definitions/error_replies.rb +2 -0
  25. data/features/step_definitions/features.rb +2 -0
  26. data/features/step_definitions/file_structure.rb +2 -0
  27. data/features/step_definitions/generic_send.rb +2 -0
  28. data/features/step_definitions/get.rb +2 -0
  29. data/features/step_definitions/help.rb +2 -0
  30. data/features/step_definitions/invalid_commands.rb +2 -0
  31. data/features/step_definitions/ipv6.rb +11 -0
  32. data/features/step_definitions/line_endings.rb +2 -0
  33. data/features/step_definitions/list.rb +2 -0
  34. data/features/step_definitions/login.rb +2 -0
  35. data/features/step_definitions/mkdir.rb +2 -0
  36. data/features/step_definitions/mode.rb +2 -0
  37. data/features/step_definitions/mtime.rb +2 -0
  38. data/features/step_definitions/noop.rb +2 -0
  39. data/features/step_definitions/options.rb +2 -0
  40. data/features/step_definitions/passive.rb +7 -0
  41. data/features/step_definitions/pending.rb +2 -0
  42. data/features/step_definitions/port.rb +2 -0
  43. data/features/step_definitions/put.rb +2 -0
  44. data/features/step_definitions/quit.rb +2 -0
  45. data/features/step_definitions/rename.rb +2 -0
  46. data/features/step_definitions/rmdir.rb +2 -0
  47. data/features/step_definitions/server_files.rb +2 -0
  48. data/features/step_definitions/server_title.rb +2 -0
  49. data/features/step_definitions/size.rb +2 -0
  50. data/features/step_definitions/status.rb +2 -0
  51. data/features/step_definitions/success_replies.rb +2 -0
  52. data/features/step_definitions/system.rb +5 -0
  53. data/features/step_definitions/timing.rb +2 -0
  54. data/features/step_definitions/type.rb +2 -0
  55. data/features/support/env.rb +2 -0
  56. data/features/support/example_server.rb +3 -1
  57. data/features/support/test_client.rb +27 -19
  58. data/features/support/test_file_templates.rb +2 -0
  59. data/features/support/test_server.rb +31 -20
  60. data/features/support/test_server_files.rb +2 -0
  61. data/ftpd.gemspec +17 -11
  62. data/lib/ftpd.rb +2 -0
  63. data/lib/ftpd/auth_levels.rb +2 -0
  64. data/lib/ftpd/cmd_abor.rb +2 -0
  65. data/lib/ftpd/cmd_allo.rb +2 -0
  66. data/lib/ftpd/cmd_appe.rb +2 -0
  67. data/lib/ftpd/cmd_auth.rb +2 -0
  68. data/lib/ftpd/cmd_cdup.rb +2 -0
  69. data/lib/ftpd/cmd_cwd.rb +2 -0
  70. data/lib/ftpd/cmd_dele.rb +2 -0
  71. data/lib/ftpd/cmd_eprt.rb +2 -0
  72. data/lib/ftpd/cmd_epsv.rb +4 -2
  73. data/lib/ftpd/cmd_feat.rb +2 -0
  74. data/lib/ftpd/cmd_help.rb +2 -0
  75. data/lib/ftpd/cmd_list.rb +2 -0
  76. data/lib/ftpd/cmd_login.rb +2 -0
  77. data/lib/ftpd/cmd_mdtm.rb +2 -0
  78. data/lib/ftpd/cmd_mkd.rb +2 -0
  79. data/lib/ftpd/cmd_mode.rb +2 -0
  80. data/lib/ftpd/cmd_nlst.rb +2 -0
  81. data/lib/ftpd/cmd_noop.rb +2 -0
  82. data/lib/ftpd/cmd_opts.rb +2 -0
  83. data/lib/ftpd/cmd_pasv.rb +5 -3
  84. data/lib/ftpd/cmd_pbsz.rb +2 -0
  85. data/lib/ftpd/cmd_port.rb +2 -0
  86. data/lib/ftpd/cmd_prot.rb +2 -0
  87. data/lib/ftpd/cmd_pwd.rb +2 -0
  88. data/lib/ftpd/cmd_quit.rb +2 -0
  89. data/lib/ftpd/cmd_rein.rb +2 -0
  90. data/lib/ftpd/cmd_rename.rb +2 -0
  91. data/lib/ftpd/cmd_rest.rb +2 -0
  92. data/lib/ftpd/cmd_retr.rb +2 -0
  93. data/lib/ftpd/cmd_rmd.rb +2 -0
  94. data/lib/ftpd/cmd_site.rb +2 -0
  95. data/lib/ftpd/cmd_size.rb +2 -0
  96. data/lib/ftpd/cmd_smnt.rb +2 -0
  97. data/lib/ftpd/cmd_stat.rb +2 -0
  98. data/lib/ftpd/cmd_stor.rb +2 -0
  99. data/lib/ftpd/cmd_stou.rb +2 -0
  100. data/lib/ftpd/cmd_stru.rb +2 -0
  101. data/lib/ftpd/cmd_syst.rb +2 -0
  102. data/lib/ftpd/cmd_type.rb +2 -0
  103. data/lib/ftpd/command_handler.rb +3 -0
  104. data/lib/ftpd/command_handler_factory.rb +2 -0
  105. data/lib/ftpd/command_handlers.rb +2 -0
  106. data/lib/ftpd/command_loop.rb +2 -0
  107. data/lib/ftpd/command_sequence_checker.rb +2 -0
  108. data/lib/ftpd/config.rb +2 -0
  109. data/lib/ftpd/connection_throttle.rb +2 -0
  110. data/lib/ftpd/connection_tracker.rb +2 -0
  111. data/lib/ftpd/data_connection_helper.rb +2 -0
  112. data/lib/ftpd/data_server_factory.rb +44 -0
  113. data/lib/ftpd/data_server_factory/random_ephemeral_port.rb +26 -0
  114. data/lib/ftpd/data_server_factory/specific_port_range.rb +37 -0
  115. data/lib/ftpd/disk_file_system.rb +2 -0
  116. data/lib/ftpd/error.rb +2 -0
  117. data/lib/ftpd/exception_translator.rb +2 -0
  118. data/lib/ftpd/exceptions.rb +2 -0
  119. data/lib/ftpd/file_info.rb +2 -0
  120. data/lib/ftpd/file_system_helper.rb +2 -0
  121. data/lib/ftpd/ftp_server.rb +27 -0
  122. data/lib/ftpd/gets_peer_address.rb +2 -0
  123. data/lib/ftpd/insecure_certificate.rb +2 -0
  124. data/lib/ftpd/list_format/eplf.rb +2 -0
  125. data/lib/ftpd/list_format/ls.rb +2 -0
  126. data/lib/ftpd/list_path.rb +2 -0
  127. data/lib/ftpd/null_logger.rb +2 -0
  128. data/lib/ftpd/protocols.rb +2 -0
  129. data/lib/ftpd/read_only_disk_file_system.rb +2 -0
  130. data/lib/ftpd/server.rb +2 -0
  131. data/lib/ftpd/session.rb +7 -0
  132. data/lib/ftpd/session_config.rb +26 -2
  133. data/lib/ftpd/stream.rb +2 -0
  134. data/lib/ftpd/telnet.rb +3 -2
  135. data/lib/ftpd/temp_dir.rb +2 -0
  136. data/lib/ftpd/tls_server.rb +2 -0
  137. data/lib/ftpd/translate_exceptions.rb +2 -0
  138. data/spec/command_sequence_checker_spec.rb +2 -0
  139. data/spec/connection_throttle_spec.rb +2 -0
  140. data/spec/connection_tracker_spec.rb +2 -0
  141. data/spec/data_server_factory_spec.rb +104 -0
  142. data/spec/disk_file_system_spec.rb +2 -0
  143. data/spec/exception_translator_spec.rb +2 -0
  144. data/spec/file_info_spec.rb +2 -0
  145. data/spec/ftp_server_error_spec.rb +2 -0
  146. data/spec/list_format/eplf_spec.rb +2 -0
  147. data/spec/list_format/ls_spec.rb +2 -0
  148. data/spec/list_path_spec.rb +2 -0
  149. data/spec/null_logger_spec.rb +2 -0
  150. data/spec/protocols_spec.rb +58 -38
  151. data/spec/server_spec.rb +2 -0
  152. data/spec/spec_helper.rb +2 -0
  153. data/spec/telnet_spec.rb +2 -0
  154. data/spec/translate_exceptions_spec.rb +2 -0
  155. data/testlib/network.rb +17 -0
  156. metadata +13 -7
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ftpd
2
4
 
3
5
  # All FTP commands which the server supports are dispatched by this
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ftpd
2
4
 
3
5
  class CommandLoop
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Some commands are supposed to occur in sequence. For example, USER
2
4
  # must be immediately followed by PASS. This class keeps track of
3
5
  # when a specific command either must arrive or must not arrive, and
data/lib/ftpd/config.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ftpd
2
4
  class Config
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ftpd
2
4
 
3
5
  # This class limits the number of connections
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "gets_peer_address"
2
4
 
3
5
  module Ftpd
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'command_handler'
2
4
 
3
5
  module Ftpd
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'data_server_factory/random_ephemeral_port'
4
+ require_relative 'data_server_factory/specific_port_range'
5
+
6
+ module Ftpd
7
+
8
+ # Factories for creating TCPServer used for passive mode
9
+ # connections.
10
+ module DataServerFactory
11
+
12
+ attr_reader :tcp_server
13
+
14
+ # Create a factory.
15
+ #
16
+ # @param interface [String] The IP address of the interface to
17
+ # bind to (e.g. "127.0.0.1")
18
+ # @param ports [nil, Range] The range of ports to bind to. If nil,
19
+ # then binds to a random ephemeral port.
20
+ def self.make(interface, ports)
21
+ if ports
22
+ SpecificPortRange.new(interface, ports)
23
+ else
24
+ RandomEphemeralPort.new(interface)
25
+ end
26
+ end
27
+
28
+ # @param interface [String] The IP address of the interface to
29
+ # bind to (e.g. "127.0.0.1")
30
+ # @param ports [nil, Range] The range of ports to bind to. If nil,
31
+ # then binds to a random ephemeral port.
32
+ def initialize(interface, ports)
33
+ @interface = interface
34
+ @ports = ports
35
+ end
36
+
37
+ # @return [TCPServer]
38
+ def make_tcp_server
39
+ TCPServer.new(@interface, 0)
40
+ end
41
+
42
+ end
43
+
44
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ftpd
4
+
5
+ module DataServerFactory
6
+
7
+ # Factory for creating TCPServer used for passive mode connections.
8
+ # This factory binds to a random ephemeral port.
9
+ class RandomEphemeralPort
10
+
11
+ # @param interface [String] The IP address of the interface to
12
+ # bind to (e.g. "127.0.0.1")
13
+ def initialize(interface)
14
+ @interface = interface
15
+ end
16
+
17
+ # @return [TCPServer]
18
+ def make_tcp_server
19
+ TCPServer.new(@interface, 0)
20
+ end
21
+
22
+ end
23
+
24
+ end
25
+
26
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ftpd
4
+
5
+ module DataServerFactory
6
+
7
+ # Factory for creating TCPServer used for passive mode
8
+ # connections. This factory binds to a random port within a
9
+ # specific range of ports.
10
+ class SpecificPortRange
11
+
12
+ # @param interface [String] The IP address of the interface to
13
+ # bind to (e.g. "127.0.0.1")
14
+ # @param ports [nil, Range] The range of ports to bind to.
15
+ def initialize(interface, ports)
16
+ @interface = interface
17
+ @ports = ports
18
+ end
19
+
20
+ # @return [TCPServer]
21
+ def make_tcp_server
22
+ ports_to_try = @ports.to_a.shuffle
23
+ until ports_to_try.empty?
24
+ port = ports_to_try.shift
25
+ begin
26
+ return TCPServer.new(@interface, port)
27
+ rescue Errno::EADDRINUSE
28
+ end
29
+ end
30
+ TCPServer.new(@interface, 0)
31
+ end
32
+
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'translate_exceptions'
2
4
 
3
5
  module Ftpd
data/lib/ftpd/error.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ftpd
2
4
  module Error
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ftpd
2
4
 
3
5
  # Translate specific exceptions to FileSystemError.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ftpd
2
4
 
3
5
  # All errors (purposefully) generated by this library driver from
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ftpd
2
4
 
3
5
  # Information about a file object (file, directory, symlink, etc.)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'command_handler'
2
4
 
3
5
  module Ftpd
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'tls_server'
2
4
 
3
5
  module Ftpd
@@ -88,6 +90,27 @@ module Ftpd
88
90
  def_delegator :@connection_throttle, :'max_connections_per_ip'
89
91
  def_delegator :@connection_throttle, :'max_connections_per_ip='
90
92
 
93
+ # The advertised public IP for passive mode connections. This is
94
+ # the IP that the client must use to make a connection back to the
95
+ # server. If nil, the IP of the bound interface is used. When
96
+ # the FTP server is behind a firewall, set this to firewall's
97
+ # public IP and add the appropriate rule to the firewall to
98
+ # forward that IP to the machine that ftpd is running on.
99
+ #
100
+ # Set this before calling #start.
101
+ #
102
+ # @return [nil, String]
103
+ attr_accessor :nat_ip
104
+
105
+ # The range of ports for passive mode connections. If nil, then a
106
+ # random etherial port is used. Otherwise, a random port from
107
+ # this range is used.
108
+ #
109
+ # Set this before calling #start.
110
+ #
111
+ # @return [nil, Range]
112
+ attr_accessor :passive_ports
113
+
91
114
  # The number of seconds to delay before replying. This is for
92
115
  # testing, when you need to test, for example, client timeouts.
93
116
  # Defaults to 0 (no delay).
@@ -164,6 +187,8 @@ module Ftpd
164
187
  @server_version = read_version_file
165
188
  @allow_low_data_ports = false
166
189
  @failed_login_delay = 0
190
+ @nat_ip = nil
191
+ @passive_ports = nil
167
192
  self.log = nil
168
193
  @connection_tracker = ConnectionTracker.new
169
194
  @connection_throttle = ConnectionThrottle.new(@connection_tracker)
@@ -194,6 +219,8 @@ module Ftpd
194
219
  config.list_formatter = @list_formatter
195
220
  config.log = @log
196
221
  config.max_failed_logins = @max_failed_logins
222
+ config.nat_ip = @nat_ip
223
+ config.passive_ports = @passive_ports
197
224
  config.response_delay = response_delay
198
225
  config.server_name = @server_name
199
226
  config.server_version = @server_version
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "gets_peer_address"
2
4
 
3
5
  module Ftpd
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ftpd
2
4
 
3
5
  # This mixin provides an insecure SSL certificate. This certificate
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ftpd
2
4
  module ListFormat
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ftpd
2
4
  module ListFormat
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ftpd
2
4
 
3
5
  # Functions for manipulating LIST and NLST arguments
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ftpd
2
4
 
3
5
  # A logger that does not log.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ftpd
2
4
 
3
5
  # With the commands EPORT and EPSV, the client sends a protocol code
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ftpd
2
4
 
3
5
  # A disk file system that does not allow any modification (writes,
data/lib/ftpd/server.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ftpd
2
4
  class Server
3
5
 
data/lib/ftpd/session.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ftpd
2
4
  class Session
3
5
 
@@ -7,6 +9,7 @@ module Ftpd
7
9
  attr_accessor :command_sequence_checker
8
10
  attr_accessor :data_channel_protection_level
9
11
  attr_accessor :data_server
12
+ attr_accessor :data_server_factory
10
13
  attr_accessor :data_type
11
14
  attr_accessor :logged_in
12
15
  attr_accessor :name_prefix
@@ -34,6 +37,10 @@ module Ftpd
34
37
  @protocols = Protocols.new(@socket)
35
38
  @command_handlers = CommandHandlers.new
36
39
  @command_loop = CommandLoop.new(self)
40
+ @data_server_factory = DataServerFactory.make(
41
+ @socket.addr[3],
42
+ config.passive_ports,
43
+ )
37
44
  register_commands
38
45
  initialize_session
39
46
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ftpd
2
4
 
3
5
  # All of the configuration needed by a session
@@ -23,8 +25,8 @@ module Ftpd
23
25
 
24
26
  attr_accessor :auth_level
25
27
 
26
- # @return driver A driver for the server's dynamic behavior such
27
- # as authentication and file system access.
28
+ # A driver for the server's dynamic behavior such as
29
+ # authentication and file system access.
28
30
  #
29
31
  # The driver should expose these public methods:
30
32
  # * {Example::Driver#authenticate authenticate}
@@ -66,6 +68,28 @@ module Ftpd
66
68
 
67
69
  attr_accessor :response_delay
68
70
 
71
+ # The advertised public IP for passive mode connections. This is
72
+ # the IP that the client must use to make a connection back to the
73
+ # server. If nil, the IP of the bound interface is used. When
74
+ # the FTP server is behind a firewall, set this to firewall's
75
+ # public IP and add the appropriate rule to the firewall to
76
+ # forward that IP to the machine that ftpd is running on.
77
+ #
78
+ # Set this before calling #start.
79
+ #
80
+ # @return [nil, String]
81
+
82
+ attr_accessor :nat_ip
83
+
84
+ # The range of ports for passive mode connections. If nil, then a
85
+ # random etherial port is used. Otherwise, a random port from
86
+ # this range is used.
87
+ #
88
+ # Set this before calling #start.
89
+ #
90
+ # @return [nil, Range]
91
+ attr_accessor :passive_ports
92
+
69
93
  # The server's name, sent in a STAT reply. Defaults to
70
94
  # {Ftpd::FtpServer::DEFAULT_SERVER_NAME}.
71
95
  #
data/lib/ftpd/stream.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ftpd
2
4
 
3
5
  class Stream
data/lib/ftpd/telnet.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # -*- ruby encoding: us-ascii -*-
2
+ # frozen_string_literal: true
2
3
 
3
4
  module Ftpd
4
5
 
@@ -97,8 +98,8 @@ module Ftpd
97
98
  # Parse the the command. Sets @plain and @reply
98
99
 
99
100
  def parse_command(command)
100
- @plain = ''
101
- @reply = ''
101
+ @plain = ''.dup
102
+ @reply = ''.dup
102
103
  scanner = StringScanner.new(command)
103
104
  while !scanner.eos?
104
105
  SEQUENCES.each do |regexp, method|
data/lib/ftpd/temp_dir.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ftpd
2
4
 
3
5
  # Create temporary directories that will be removed when the program
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'server'
2
4
 
3
5
  module Ftpd
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ftpd
2
4
 
3
5
  # This module translates exceptions to FileSystemError exceptions.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require File.expand_path('spec_helper', File.dirname(__FILE__))
2
4
 
3
5
  module Ftpd