ftpd 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,36 @@
1
+ ### 0.5.0
2
+
3
+ Bug fixes
4
+
5
+ * Replies are sent with the correct line ending ("\r\n" instead of
6
+ "\n")
7
+ * Do not hang on out-of-band commands.
8
+ * When data connection disconnects, send "426 Connection closed"
9
+ response instead of ending the session.
10
+
11
+ Enhancements
12
+
13
+ * Now unconditionally compliant
14
+ * Configurable session timeout (see {Ftpd::FtpServer#session_timeout}).
15
+ Defaults to 5 minutes.
16
+ * Disable Nagle algorithm on control connection to decrease latency.
17
+ This makes the tests run much faster.
18
+ * Support STAT (server status).
19
+ * Example has --timeout option for session idle timeout.
20
+ * Write log to Logger (see {Ftpd::FtpServer#log}).
21
+ * Disallow active-mode connections to privileged ports (configurable).
22
+ See RFC 2577 section 3.
23
+ * Added benchmarks.
24
+ * Support telnet sequences.
25
+
26
+ API Changes
27
+
28
+ * Added {Ftpd::FtpServer#server_name}
29
+ * Added {Ftpd::FtpServer#server_version}
30
+ * Removed #debug and #debug_path from Ftpd::FtpServer. They have been
31
+ replaced with #log
32
+ # Added {Ftpd::FtpServer#allow_low_data_ports}
33
+
1
34
  ### 0.4.0
2
35
 
3
36
  Enhancements
data/Gemfile CHANGED
@@ -5,6 +5,7 @@ gem 'memoizer', '~> 1.0.1'
5
5
  group :development do
6
6
  gem 'cucumber'
7
7
  gem 'double-bag-ftps', :git => 'git@github.com:wconrad/double-bag-ftps.git'
8
+ gem 'fuubar-cucumber'
8
9
  gem 'jeweler'
9
10
  gem 'rake'
10
11
  gem 'redcarpet'
@@ -14,6 +14,9 @@ GEM
14
14
  gherkin (~> 2.11.0)
15
15
  json (>= 1.4.6)
16
16
  diff-lcs (1.2.1)
17
+ fuubar-cucumber (0.0.18)
18
+ cucumber (~> 1.2.0)
19
+ ruby-progressbar (~> 1.0.0)
17
20
  gherkin (2.11.6)
18
21
  json (>= 1.7.6)
19
22
  git (1.2.5)
@@ -36,6 +39,7 @@ GEM
36
39
  rspec-expectations (2.13.0)
37
40
  diff-lcs (>= 1.1.3, < 2.0)
38
41
  rspec-mocks (2.13.0)
42
+ ruby-progressbar (1.0.2)
39
43
  timecop (0.5.9.2)
40
44
  yard (0.8.5.2)
41
45
 
@@ -45,6 +49,7 @@ PLATFORMS
45
49
  DEPENDENCIES
46
50
  cucumber
47
51
  double-bag-ftps!
52
+ fuubar-cucumber
48
53
  jeweler
49
54
  memoizer (~> 1.0.1)
50
55
  rake
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # FTPD
2
2
 
3
3
  ftpd is a pure Ruby FTP server library. It supports implicit and
4
- explicit TLS, passive and active mode, and most of the commands
5
- specified in RFC 969. It an be used as part of a test fixture or
4
+ explicit TLS, passive and active mode, and is unconditionally
5
+ complaint per RFC-1123. It an be used as part of a test fixture or
6
6
  embedded in a program.
7
7
 
8
8
  ## A note about this README
@@ -10,7 +10,7 @@ embedded in a program.
10
10
  This readme, and the other files, contains Yardoc markup, especially
11
11
  for links to the API docs; those links don't display properly on
12
12
  github. You'll find a properly rendered version
13
- {http://rubydoc.info/gems/ftpd on rubydoc.info}
13
+ [on rubydoc.info](http://rubydoc.info/gems/ftpd)
14
14
 
15
15
  ## HELLO WORLD
16
16
 
@@ -83,14 +83,17 @@ file system.
83
83
  Here are the methods a file system may expose:
84
84
 
85
85
  * {Ftpd::DiskFileSystem::Accessors#accessible? accessible?}
86
- * {Ftpd::DiskFileSystem::Accessors#exists? exists?}
87
86
  * {Ftpd::DiskFileSystem::Accessors#directory? directory?}
88
- * {Ftpd::DiskFileSystem::Write#write write}
89
- * {Ftpd::DiskFileSystem::Mkdir#mkdir mkdir}
90
- * {Ftpd::DiskFileSystem::Rmdir#rmdir rmdir}
91
- * {Ftpd::DiskFileSystem::List#file_info file_info}
87
+ * {Ftpd::DiskFileSystem::Accessors#exists? exists?}
88
+ * {Ftpd::DiskFileSystem::Append#append append}
89
+ * {Ftpd::DiskFileSystem::Delete#delete delete}
92
90
  * {Ftpd::DiskFileSystem::List#dir dir}
91
+ * {Ftpd::DiskFileSystem::List#file_info file_info}
92
+ * {Ftpd::DiskFileSystem::Mkdir#mkdir mkdir}
93
+ * {Ftpd::DiskFileSystem::Read#read read}
93
94
  * {Ftpd::DiskFileSystem::Rename#rename rename}
95
+ * {Ftpd::DiskFileSystem::Rmdir#rmdir rmdir}
96
+ * {Ftpd::DiskFileSystem::Write#write write}
94
97
 
95
98
  ### DiskFileSystem
96
99
 
@@ -113,6 +116,7 @@ file system, then use {Ftpd::ReadOnlyDiskFileSystem} instead.
113
116
  The DiskFileSystem is composed out of modules:
114
117
 
115
118
  * {Ftpd::DiskFileSystem::Base Base} - You will need this
119
+ * {Ftpd::DiskFileSystem::Append Append} - File appending
116
120
  * {Ftpd::DiskFileSystem::Delete Delete} - File deletion
117
121
  * {Ftpd::DiskFileSystem::List List} - Directory listing
118
122
  * {Ftpd::DiskFileSystem::Mkdir Mkdir} - Directory creation
@@ -148,7 +152,7 @@ By default, the LIST command uses Unix "ls -l" formatting:
148
152
  -rw-r--r-- 1 user group 1234 Mar 3 08:38 foo
149
153
 
150
154
  To switch to
151
- {http://cr.yp.to/ftp/list/eplf.html Easily Parsed LIST format (EPLF)}
155
+ [Easily Parsed LIST format (EPLF)](http://cr.yp.to/ftp/list/eplf.html)
152
156
  format:
153
157
 
154
158
  ftp_server.list_formatter = Ftpd::ListFormat::Eplf
@@ -181,27 +185,15 @@ Debug output can also be enabled by setting the environment variable
181
185
  FTPD_DEBUG to a non-zero value. This is a convenient way to get debug
182
186
  output without having to change any code.
183
187
 
184
- ## LIMITATIONS
185
-
186
- Ftpd is not fully RFC compliant. It does most of RFC969, and enough
187
- TLS to get by. {file:doc/rfc.md Here} is a list of RFCs, indicating
188
- how much of each Ftpd complies with.
189
-
190
- RFC does not meet the following
191
- [RFC-1123](http://tools.ietf.org/rfc/rfc1123.txt) "MUST" requrements.
192
- If FTPD met these requirements, but did not meet the "SHOULD"
193
- requirements, it would be "conditionally compliant":
188
+ ## STANDARDS COMPLIANCE
194
189
 
195
- * Server-FTP handle Telnet options
196
- * Support command STAT
190
+ Ftpd is fully unconditionally compliant per [RFC-1123 Requirements for
191
+ Internet Hosts](http://tools.ietf.org/rfc/rfc1123.txt).
197
192
 
198
- RFC does not meet the following
199
- [RFC-1123](http://tools.ietf.org/rfc/rfc1123.txt)
200
- "SHOULD" requrements. If FTPD met both the "MUST" and the "SHOULD"
201
- requirements, it would be "unconditionally compliant":
193
+ Ftpd implements enough of [RFC-4217 Securing FTP with
194
+ TLS](http://tools.ietf.org/rfc/rfc4217.txt) to get by.
202
195
 
203
- * Idle timeout in server-FTP
204
- * Configurable idle timeout
196
+ See [RFC Compliance](doc/rfc-compliance.md) for details
205
197
 
206
198
  ## RUBY COMPATABILITY
207
199
 
@@ -231,6 +223,12 @@ or just:
231
223
 
232
224
  $ rake
233
225
 
226
+ To force features to write the server log to stdout:
227
+
228
+ $ FTPD_DEBUG=1 rake test:features
229
+
230
+ ### Example
231
+
234
232
  To run the stand-alone example:
235
233
 
236
234
  $ examples/example.rb
@@ -256,6 +254,7 @@ and granted permission to donate it to the community.
256
254
 
257
255
  ## See also
258
256
 
259
- * {file:Changelog.md}
260
- * {file:doc/rfc-compliance.md RFC compliance}
261
- * {file:doc/references.md}
257
+ * [Changelog](Changelog.md)
258
+ * [RFC compliance](doc/rfc-compliance.md)
259
+ * [References](doc/references.md)
260
+ * [Benchmarks](doc/benchmarks.md)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.0
1
+ 0.5.0
@@ -0,0 +1,2 @@
1
+ ---
2
+ default: --format Cucumber::Formatter::Fuubar
@@ -0,0 +1,92 @@
1
+ # Benchmarks
2
+
3
+ Benchmarks using pyftpd's [benchmark
4
+ script](http://pyftpdlib.googlecode.com/svn/trunk/test/bench.py) and
5
+ [procedures](http://code.google.com/p/pyftpdlib/wiki/Benchmarks).
6
+
7
+ ## Results
8
+
9
+ ### ftpd 0.4.0
10
+
11
+ (starting with 13.6M of RSS memory being used)
12
+ STOR (client -> server) 845.55 MB/sec 13.6M RSS
13
+ RETR (server -> client) 1234.80 MB/sec 859.5M RSS
14
+ 200 concurrent clients (connect, login) 0.14 secs 863.0M RSS
15
+ STOR (1 file with 200 idle clients) 848.56 MB/sec 863.0M RSS
16
+ RETR (1 file with 200 idle clients) 1227.46 MB/sec 866.4M RSS
17
+ 200 concurrent clients (RETR 10.0M file) 5.36 secs 2.0G RSS
18
+ 200 concurrent clients (STOR 10.0M file) 4.65 secs 2.0G RSS
19
+ 200 concurrent clients (QUIT) 0.01 secs
20
+
21
+ ### pyftpdlib 1.0.1
22
+
23
+ (starting with 8.9M of RSS memory being used)
24
+ STOR (client -> server) 81.73 MB/sec 8.9M RSS
25
+ RETR (server -> client) 1001.05 MB/sec 8.9M RSS
26
+ 200 concurrent clients (connect, login) 2.58 secs 9.6M RSS
27
+ STOR (1 file with 200 idle clients) 108.46 MB/sec 9.6M RSS
28
+ RETR (1 file with 200 idle clients) 1134.18 MB/sec 9.6M RSS
29
+ 200 concurrent clients (RETR 10.0M file) 2.32 secs 10.3M RSS
30
+ 200 concurrent clients (STOR 10.0M file) 4.12 secs 10.4M RSS
31
+ 200 concurrent clients (QUIT) 0.02 secs
32
+
33
+ ### proftpd 1.3.4a-3
34
+
35
+ (starting with 2.3M of RSS memory being used)
36
+ STOR (client -> server) 93.06 MB/sec 6.6M RSS
37
+ RETR (server -> client) 1267.63 MB/sec 6.6M RSS
38
+ 200 concurrent clients (connect, login) 14.21 secs 868.0M RSS
39
+ STOR (1 file with 200 idle clients) 76.04 MB/sec 872.3M RSS
40
+ RETR (1 file with 200 idle clients) 1289.75 MB/sec 872.3M RSS
41
+ 200 concurrent clients (RETR 10.0M file) 2.04 secs 868.0M RSS
42
+ 200 concurrent clients (STOR 10.0M file) 4.51 secs 868.2M RSS
43
+ 200 concurrent clients (QUIT) 0.00 secs
44
+
45
+ ### Discussion
46
+
47
+ ftpd's STOR results seen anomalous. I suspect that proftpd and
48
+ pyftpdlib aren't getting a fair shake here. proftpd and pyftpdlib are
49
+ serving my home directory, whereas ftpd is serving a temporary
50
+ directory, but I don't know what difference that could make.
51
+
52
+ Ftpd is a memory hog. During a STOR or RETR, it loads the entire
53
+ contents of a file into memory. This limits the number of concurrent
54
+ file transfers it can handle. The pyftpd team uses -n 300 (300
55
+ concurrent connections) when benchmarking, but Ftpd can't handle that
56
+ many at the moment.
57
+
58
+ Ftpd's fast time on the login test, compared to proftpd and pyftpdlib,
59
+ is a result of it not doing PAM authentication. It is an unfair
60
+ comparison and should be disregarded.
61
+
62
+ pyftpd's memory footprint is impressive.
63
+
64
+ ftpd is less performant with many concurrent connections than either
65
+ proftpd or pyftpdlib.
66
+
67
+ ## Setup
68
+
69
+ ### Machine
70
+
71
+ * Intel(R) Core(TM) i5-2500 CPU @ 3.30GHz (4 cores)
72
+ * Python 2.7.3rc2 (default, Apr 22 2012, 22:35:38)
73
+ * ruby 2.0.0p0 (2013-02-24 revision 39474) [i686-linux]
74
+ * Linux 3.0.0-1-686-pae #1 SMP Sat Aug 27 16:41:03 UTC 2011 i686 GNU/Linux
75
+
76
+ ### Benchmark command
77
+
78
+ $ python bench.py -u <USER> -p <PASS> -H localhost -p <PORT> -b all -n 200 -k <PID>
79
+
80
+ ### Proftpd
81
+
82
+ /etc/proftpd/proftpd.conf:
83
+
84
+ MaxInstances 2000
85
+
86
+ ### Ftpd
87
+
88
+ $ bundle exec examples/example.rb -p 2222 -U bench -P bench
89
+
90
+ ### Pyftpd
91
+
92
+ pyftpdlib-1.0.0/demo$ sudo python unix_daemon.py 2>/dev/null
@@ -9,15 +9,38 @@ Copyright (c) 2008 James Healy_
9
9
  There are a range of RFCs that together specify the FTP protocol. In
10
10
  chronological order, the more useful ones are:
11
11
 
12
- * {http://tools.ietf.org/rfc/rfc959.txt RFC-959} - File Transfer Protocol
13
- * {http://tools.ietf.org/rfc/rfc1123.txt RFC-1123} - Requirements for Internet Hosts
14
- * {http://tools.ietf.org/rfc/rfc2228.txt RFC-2228} - FTP Security Extensions
15
- * {http://tools.ietf.org/rfc/rfc2389.txt RFC-2389} - Feature negotiation mechanism for the File Transfer Protocol
16
- * {http://tools.ietf.org/rfc/rfc2428.txt RFC-2428} - FTP Extensions for IPv6 and NATs
17
- * {http://tools.ietf.org/rfc/rfc2577.txt RFC-2577} - FTP Security Considerations
18
- * {http://tools.ietf.org/rfc/rfc2640.txt RFC-2640} - Internationalization of the File Transfer Protocol
19
- * {http://tools.ietf.org/rfc/rfc3659.txt RFC-3659} - Extensions to FTP
20
- * {http://tools.ietf.org/rfc/rfc4217.txt RFC-4217} - Internationalization of the File Transfer Protocol
12
+ * [RFC-854](http://tools.ietf.org/rfc/rfc854.txt) - Telnet Protocol
13
+ Specification
14
+
15
+ * [RFC-959](http://tools.ietf.org/rfc/rfc959.txt) - File Transfer
16
+ Protocol
17
+
18
+ * [RFC-1123](http://tools.ietf.org/rfc/rfc1123.txt) - Requirements for
19
+ Internet Hosts
20
+
21
+ * [RFC-1143](http://tools.ietf.org/rfc/rfc1143.txt) - The Q Method of
22
+ Implementing TELNET Option Negotation
23
+
24
+ * [RFC-2228](http://tools.ietf.org/rfc/rfc2228.txt) - FTP Security
25
+ Extensions
26
+
27
+ * [RFC-2389](http://tools.ietf.org/rfc/rfc2389.txt) - Feature
28
+ negotiation mechanism for the File Transfer Protocol
29
+
30
+ * [RFC-2428](http://tools.ietf.org/rfc/rfc2428.txt) - FTP Extensions
31
+ for IPv6 and NATs
32
+
33
+ * [RFC-2577](http://tools.ietf.org/rfc/rfc2577.txt) - FTP Security
34
+ Considerations
35
+
36
+ * [RFC-2640](http://tools.ietf.org/rfc/rfc2640.txt) -
37
+ Internationalization of the File Transfer Protocol
38
+
39
+ * [RFC-3659](http://tools.ietf.org/rfc/rfc3659.txt) - Extensions to
40
+ FTP
41
+
42
+ * [RFC-4217](http://tools.ietf.org/rfc/rfc4217.txt) -
43
+ Internationalization of the File Transfer Protocol
21
44
 
22
45
  For an english summary that's somewhat more legible than the RFCs, and
23
46
  provides some commentary on what features are actually useful or
@@ -29,11 +52,15 @@ For a history lesson, check out Appendix III of RCF959. It lists the
29
52
  preceding (obsolete) RFC documents that relate to file transfers,
30
53
  including the ye old RFC114 from 1971, "A File Transfer Protocol"
31
54
 
32
- There is a {http://secureftp-test.com public test server} which is
55
+ There is a [public test server](http://secureftp-test.com) which is
33
56
  very handy for checking out clients, and seeing how at least one
34
57
  server behaves.
35
58
 
59
+ ## How to reliably close a socket (and not lose data)
60
+
61
+ [Why is my TCP not reliable](http://ia600609.us.archive.org/22/items/TheUltimateSo_lingerPageOrWhyIsMyTcpNotReliable/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable.html) by Bert Hubert
62
+
36
63
  ## LIST output format
37
64
 
38
- * {http://www.gnu.org/software/coreutils/manual/html_node/What-information-is-listed.html#What-information-is-listed GNU docs for ls}
39
- * {http://cr.yp.to/ftp/list/eplf.html Easily Parsed LIST format (EPLF)}
65
+ * [GNU docs for ls](http://www.gnu.org/software/coreutils/manual/html_node/What-information-is-listed.html#What-information-is-listed)
66
+ * [Easily Parsed LIST format (EPLF)](http://cr.yp.to/ftp/list/eplf.html)
@@ -50,7 +50,7 @@ Commands supported:
50
50
  RNTO Yes 0.2.1 Rename file (to)
51
51
  SITE No --- Site specific commands
52
52
  SMNT No --- Structure Mount
53
- STAT No --- Server status
53
+ STAT Yes 0.5.0 Server status
54
54
  STOR Yes 0.1.0 Store file
55
55
  STOU Yes 0.2.2 Store with unique name
56
56
  STRU Yes 0.1.0 Set file structure
@@ -100,10 +100,10 @@ Server-FTP send only correct reply format |4.1.2.11 |x| | | | | C
100
100
  Server-FTP use defined reply code if poss. |4.1.2.11 | |x| | | | C
101
101
  New reply code following Section 4.2 |4.1.2.11 | | |x| | | E
102
102
  Default data port same IP addr as ctl conn |4.1.2.12 |x| | | | | C
103
- Server-FTP handle Telnet options |4.1.2.12 |x| | | | |
103
+ Server-FTP handle Telnet options |4.1.2.12 |x| | | | | C
104
104
  Handle "Experimental" directory cmds |4.1.3.1 | |x| | | | C
105
- Idle timeout in server-FTP |4.1.3.2 | |x| | | |
106
- Configurable idle timeout |4.1.3.2 | |x| | | |
105
+ Idle timeout in server-FTP |4.1.3.2 | |x| | | | C
106
+ Configurable idle timeout |4.1.3.2 | |x| | | | C
107
107
  Receiver checkpoint data at Restart Marker |4.1.3.4 | |x| | | |
108
108
  Sender assume 110 replies are synchronous |4.1.3.4 | | | | |x|
109
109
  | | | | | | |
@@ -157,7 +157,7 @@ Support commands: | | | | | | |
157
157
  LIST |4.1.2.13 |x| | | | | C
158
158
  NLST |4.1.2.13 |x| | | | | C
159
159
  SITE |4.1.2.8 | | |x| | | E
160
- STAT |4.1.2.13 |x| | | | |
160
+ STAT |4.1.2.13 |x| | | | | C
161
161
  SYST |4.1.2.13 |x| | | | | C
162
162
  HELP |4.1.2.13 |x| | | | | C
163
163
  NOOP |4.1.2.13 |x| | | | | C
@@ -230,7 +230,7 @@ attempts and third-party "proxy FTP" transfers, which can be used in
230
230
 
231
231
  <pre>
232
232
  FTP bounce protection
233
- Restrict PASV/PORT to non-priv. ports No ---
233
+ Restrict PASV/PORT to non-priv. ports Yes 0.5.0
234
234
  Disconnect after so many wrong auths. No ---
235
235
  Delay on invalid password No ---
236
236
  Per-source IP limit No ---
@@ -15,11 +15,13 @@ module Example
15
15
 
16
16
  attr_reader :account
17
17
  attr_reader :auth_level
18
+ attr_reader :debug
18
19
  attr_reader :eplf
19
20
  attr_reader :interface
20
21
  attr_reader :password
21
22
  attr_reader :port
22
23
  attr_reader :read_only
24
+ attr_reader :session_timeout
23
25
  attr_reader :tls
24
26
  attr_reader :user
25
27
 
@@ -31,6 +33,8 @@ module Example
31
33
  @user = ENV['LOGNAME']
32
34
  @password = ''
33
35
  @account = ''
36
+ @session_timeout = default_session_timeout
37
+ @log = nil
34
38
  op = option_parser
35
39
  op.parse!(argv)
36
40
  rescue OptionParser::ParseError => e
@@ -76,9 +80,20 @@ module Example
76
80
  'defaults to empty string') do |t|
77
81
  @account = t
78
82
  end
83
+ op.on('--timeout SEC', Integer, 'Session idle timeout',
84
+ "defaults to #{default_session_timeout}") do |t|
85
+ @session_timeout = t
86
+ end
87
+ op.on('-d', '--debug', 'Write server debug log to stdout') do |t|
88
+ @debug = t
89
+ end
79
90
  end
80
91
  end
81
92
 
93
+ def default_session_timeout
94
+ Ftpd::FtpServer::DEFAULT_SESSION_TIMEOUT
95
+ end
96
+
82
97
  end
83
98
  end
84
99
 
@@ -157,6 +172,8 @@ module Example
157
172
  @server.list_formatter = Ftpd::ListFormat::Eplf
158
173
  end
159
174
  @server.auth_level = auth_level
175
+ @server.session_timeout = @args.session_timeout
176
+ @server.log = make_log
160
177
  @server.start
161
178
  display_connection_info
162
179
  create_connection_script
@@ -231,6 +248,10 @@ module Example
231
248
  @args.account
232
249
  end
233
250
 
251
+ def make_log
252
+ @args.debug && Logger.new($stdout)
253
+ end
254
+
234
255
  end
235
256
  end
236
257