ftpd 1.1.1 → 2.0.0

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