ftpd 1.1.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/Changelog.md +15 -0
- data/Gemfile +2 -2
- data/Gemfile.lock +57 -48
- data/README.md +8 -1
- data/VERSION +1 -1
- data/examples/example.rb +12 -0
- data/features/example/step_definitions/example_server.rb +2 -0
- data/features/ftp_server/eprt.feature +1 -0
- data/features/ftp_server/epsv.feature +1 -0
- data/features/ftp_server/get_ipv6.feature +3 -0
- data/features/ftp_server/pasv.feature +10 -3
- data/features/ftp_server/step_definitions/logging.rb +2 -0
- data/features/ftp_server/step_definitions/test_server.rb +6 -0
- data/features/step_definitions/append.rb +2 -0
- data/features/step_definitions/client.rb +3 -0
- data/features/step_definitions/client_and_server_files.rb +2 -0
- data/features/step_definitions/client_files.rb +2 -0
- data/features/step_definitions/command.rb +2 -0
- data/features/step_definitions/connect.rb +2 -0
- data/features/step_definitions/delete.rb +2 -0
- data/features/step_definitions/directory_navigation.rb +2 -0
- data/features/step_definitions/error_replies.rb +2 -0
- data/features/step_definitions/features.rb +2 -0
- data/features/step_definitions/file_structure.rb +2 -0
- data/features/step_definitions/generic_send.rb +2 -0
- data/features/step_definitions/get.rb +2 -0
- data/features/step_definitions/help.rb +2 -0
- data/features/step_definitions/invalid_commands.rb +2 -0
- data/features/step_definitions/ipv6.rb +11 -0
- data/features/step_definitions/line_endings.rb +2 -0
- data/features/step_definitions/list.rb +2 -0
- data/features/step_definitions/login.rb +2 -0
- data/features/step_definitions/mkdir.rb +2 -0
- data/features/step_definitions/mode.rb +2 -0
- data/features/step_definitions/mtime.rb +2 -0
- data/features/step_definitions/noop.rb +2 -0
- data/features/step_definitions/options.rb +2 -0
- data/features/step_definitions/passive.rb +7 -0
- data/features/step_definitions/pending.rb +2 -0
- data/features/step_definitions/port.rb +2 -0
- data/features/step_definitions/put.rb +2 -0
- data/features/step_definitions/quit.rb +2 -0
- data/features/step_definitions/rename.rb +2 -0
- data/features/step_definitions/rmdir.rb +2 -0
- data/features/step_definitions/server_files.rb +2 -0
- data/features/step_definitions/server_title.rb +2 -0
- data/features/step_definitions/size.rb +2 -0
- data/features/step_definitions/status.rb +2 -0
- data/features/step_definitions/success_replies.rb +2 -0
- data/features/step_definitions/system.rb +5 -0
- data/features/step_definitions/timing.rb +2 -0
- data/features/step_definitions/type.rb +2 -0
- data/features/support/env.rb +2 -0
- data/features/support/example_server.rb +3 -1
- data/features/support/test_client.rb +27 -19
- data/features/support/test_file_templates.rb +2 -0
- data/features/support/test_server.rb +31 -20
- data/features/support/test_server_files.rb +2 -0
- data/ftpd.gemspec +17 -11
- data/lib/ftpd.rb +2 -0
- data/lib/ftpd/auth_levels.rb +2 -0
- data/lib/ftpd/cmd_abor.rb +2 -0
- data/lib/ftpd/cmd_allo.rb +2 -0
- data/lib/ftpd/cmd_appe.rb +2 -0
- data/lib/ftpd/cmd_auth.rb +2 -0
- data/lib/ftpd/cmd_cdup.rb +2 -0
- data/lib/ftpd/cmd_cwd.rb +2 -0
- data/lib/ftpd/cmd_dele.rb +2 -0
- data/lib/ftpd/cmd_eprt.rb +2 -0
- data/lib/ftpd/cmd_epsv.rb +4 -2
- data/lib/ftpd/cmd_feat.rb +2 -0
- data/lib/ftpd/cmd_help.rb +2 -0
- data/lib/ftpd/cmd_list.rb +2 -0
- data/lib/ftpd/cmd_login.rb +2 -0
- data/lib/ftpd/cmd_mdtm.rb +2 -0
- data/lib/ftpd/cmd_mkd.rb +2 -0
- data/lib/ftpd/cmd_mode.rb +2 -0
- data/lib/ftpd/cmd_nlst.rb +2 -0
- data/lib/ftpd/cmd_noop.rb +2 -0
- data/lib/ftpd/cmd_opts.rb +2 -0
- data/lib/ftpd/cmd_pasv.rb +5 -3
- data/lib/ftpd/cmd_pbsz.rb +2 -0
- data/lib/ftpd/cmd_port.rb +2 -0
- data/lib/ftpd/cmd_prot.rb +2 -0
- data/lib/ftpd/cmd_pwd.rb +2 -0
- data/lib/ftpd/cmd_quit.rb +2 -0
- data/lib/ftpd/cmd_rein.rb +2 -0
- data/lib/ftpd/cmd_rename.rb +2 -0
- data/lib/ftpd/cmd_rest.rb +2 -0
- data/lib/ftpd/cmd_retr.rb +2 -0
- data/lib/ftpd/cmd_rmd.rb +2 -0
- data/lib/ftpd/cmd_site.rb +2 -0
- data/lib/ftpd/cmd_size.rb +2 -0
- data/lib/ftpd/cmd_smnt.rb +2 -0
- data/lib/ftpd/cmd_stat.rb +2 -0
- data/lib/ftpd/cmd_stor.rb +2 -0
- data/lib/ftpd/cmd_stou.rb +2 -0
- data/lib/ftpd/cmd_stru.rb +2 -0
- data/lib/ftpd/cmd_syst.rb +2 -0
- data/lib/ftpd/cmd_type.rb +2 -0
- data/lib/ftpd/command_handler.rb +3 -0
- data/lib/ftpd/command_handler_factory.rb +2 -0
- data/lib/ftpd/command_handlers.rb +2 -0
- data/lib/ftpd/command_loop.rb +2 -0
- data/lib/ftpd/command_sequence_checker.rb +2 -0
- data/lib/ftpd/config.rb +2 -0
- data/lib/ftpd/connection_throttle.rb +2 -0
- data/lib/ftpd/connection_tracker.rb +2 -0
- data/lib/ftpd/data_connection_helper.rb +2 -0
- data/lib/ftpd/data_server_factory.rb +44 -0
- data/lib/ftpd/data_server_factory/random_ephemeral_port.rb +26 -0
- data/lib/ftpd/data_server_factory/specific_port_range.rb +37 -0
- data/lib/ftpd/disk_file_system.rb +2 -0
- data/lib/ftpd/error.rb +2 -0
- data/lib/ftpd/exception_translator.rb +2 -0
- data/lib/ftpd/exceptions.rb +2 -0
- data/lib/ftpd/file_info.rb +2 -0
- data/lib/ftpd/file_system_helper.rb +2 -0
- data/lib/ftpd/ftp_server.rb +27 -0
- data/lib/ftpd/gets_peer_address.rb +2 -0
- data/lib/ftpd/insecure_certificate.rb +2 -0
- data/lib/ftpd/list_format/eplf.rb +2 -0
- data/lib/ftpd/list_format/ls.rb +2 -0
- data/lib/ftpd/list_path.rb +2 -0
- data/lib/ftpd/null_logger.rb +2 -0
- data/lib/ftpd/protocols.rb +2 -0
- data/lib/ftpd/read_only_disk_file_system.rb +2 -0
- data/lib/ftpd/server.rb +2 -0
- data/lib/ftpd/session.rb +7 -0
- data/lib/ftpd/session_config.rb +26 -2
- data/lib/ftpd/stream.rb +2 -0
- data/lib/ftpd/telnet.rb +3 -2
- data/lib/ftpd/temp_dir.rb +2 -0
- data/lib/ftpd/tls_server.rb +2 -0
- data/lib/ftpd/translate_exceptions.rb +2 -0
- data/spec/command_sequence_checker_spec.rb +2 -0
- data/spec/connection_throttle_spec.rb +2 -0
- data/spec/connection_tracker_spec.rb +2 -0
- data/spec/data_server_factory_spec.rb +104 -0
- data/spec/disk_file_system_spec.rb +2 -0
- data/spec/exception_translator_spec.rb +2 -0
- data/spec/file_info_spec.rb +2 -0
- data/spec/ftp_server_error_spec.rb +2 -0
- data/spec/list_format/eplf_spec.rb +2 -0
- data/spec/list_format/ls_spec.rb +2 -0
- data/spec/list_path_spec.rb +2 -0
- data/spec/null_logger_spec.rb +2 -0
- data/spec/protocols_spec.rb +58 -38
- data/spec/server_spec.rb +2 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/telnet_spec.rb +2 -0
- data/spec/translate_exceptions_spec.rb +2 -0
- data/testlib/network.rb +17 -0
- metadata +13 -7
data/lib/ftpd/command_loop.rb
CHANGED
data/lib/ftpd/config.rb
CHANGED
@@ -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
|
data/lib/ftpd/error.rb
CHANGED
data/lib/ftpd/exceptions.rb
CHANGED
data/lib/ftpd/file_info.rb
CHANGED
data/lib/ftpd/ftp_server.rb
CHANGED
@@ -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
|
data/lib/ftpd/list_format/ls.rb
CHANGED
data/lib/ftpd/list_path.rb
CHANGED
data/lib/ftpd/null_logger.rb
CHANGED
data/lib/ftpd/protocols.rb
CHANGED
data/lib/ftpd/server.rb
CHANGED
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
|
data/lib/ftpd/session_config.rb
CHANGED
@@ -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
|
-
#
|
27
|
-
#
|
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
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
data/lib/ftpd/tls_server.rb
CHANGED