Search code examples
rubyftpnet-ftp

Errno::EPIPE: Broken pipe with Net::FTP


Similar to this question, I can connect and even check/change the working directory, but calling list throws a Errno::EPIPE: Broken pipe error.

So far I've only seen this from Terminal (OS X). I've tried a couple different hosts, which I've verified I can access normally with FileZilla. I've also verified I can list files via a regular ol' command-line ftp session.

Could this be a firewall issue? Or an issue with my shell?

Here's an example IRB session...

irb> ftp = Net::FTP.new 'host.domain.com' 
 => #<Net::FTP:0x007fc10d053ab8 @mon_owner=nil, @mon_count=0, @mon_mutex=#<Mutex:0x007fc10d053a68>, @binary=true, @passive=false, @debug_mode=false, @resume=false, @sock=#<TCPSocket:fd 7>, @logged_in=false, @last_response="220 ESS FTP\n", @last_response_code="220"> 
irb> ftp.debug_mode = true
 => true 
irb> ftp.login 'user', '*********'
put: USER user
get: 331 Password required for user
put: PASS *********
get: 230 Logged on
put: TYPE I
get: 200 Type set to I
 => true 
irb> ftp.pwd
put: PWD
get: 257 "/" is current directory.
  => "/" 
irb> ftp.chdir 'Inventory'
put: CWD Inventory
get: 250 CWD successful. "/Inventory" is current directory.
irb> ftp.list
put: TYPE A
get: 200 Type set to A
put: PORT 10,142,96,98,199,111
put: TYPE I
Errno::EPIPE: Broken pipe
  from /Users/acobster/.rvm/rubies/ruby-1.9.3-p392/lib/ruby/1.9.1/net/ftp.rb:257:in `write'
  from /Users/acobster/.rvm/rubies/ruby-1.9.3-p392/lib/ruby/1.9.1/net/ftp.rb:257:in `putline'
  from /Users/acobster/.rvm/rubies/ruby-1.9.3-p392/lib/ruby/1.9.1/net/ftp.rb:334:in `block in voidcmd'
  from /Users/acobster/.rvm/rubies/ruby-1.9.3-p392/lib/ruby/1.9.1/monitor.rb:211:in `mon_synchronize'
  from /Users/acobster/.rvm/rubies/ruby-1.9.3-p392/lib/ruby/1.9.1/net/ftp.rb:333:in `voidcmd'
  from /Users/acobster/.rvm/rubies/ruby-1.9.3-p392/lib/ruby/1.9.1/net/ftp.rb:162:in `send_type_command'
  from /Users/acobster/.rvm/rubies/ruby-1.9.3-p392/lib/ruby/1.9.1/net/ftp.rb:151:in `binary='
  from /Users/acobster/.rvm/rubies/ruby-1.9.3-p392/lib/ruby/1.9.1/net/ftp.rb:180:in `ensure in with_binary'
  from /Users/acobster/.rvm/rubies/ruby-1.9.3-p392/lib/ruby/1.9.1/net/ftp.rb:180:in `with_binary'
  from /Users/acobster/.rvm/rubies/ruby-1.9.3-p392/lib/ruby/1.9.1/net/ftp.rb:477:in `block in retrlines'
  from /Users/acobster/.rvm/rubies/ruby-1.9.3-p392/lib/ruby/1.9.1/monitor.rb:211:in `mon_synchronize'
  from /Users/acobster/.rvm/rubies/ruby-1.9.3-p392/lib/ruby/1.9.1/net/ftp.rb:476:in `retrlines'
  from /Users/acobster/.rvm/rubies/ruby-1.9.3-p392/lib/ruby/1.9.1/net/ftp.rb:722:in `list'
  from (irb):9
  from /Users/acobster/.rvm/rubies/ruby-1.9.3-p392/bin/irb:16:in `<main>'

Please help, thanks!

Update: I can do ftp.list from an IRB session on a remote server...

$ ssh myserver
server $ irb
irb> ftp = Net::FTP.new 'host.domain.com' 
=> #<Net::FTP:0x2b7d3c5edc80 @last_response="220 ESS FTP\n", @debug_mode=false, @mon_entering_queue=[], @sock=#<TCPSocket:0x2b7d3c5edb18>, @passive=false, @mon_count=0, @binary=true, @mon_owner=nil, @last_response_code="220", @resume=false, @mon_waiting_queue=[]>
irb> ftp.login 'user', 'pass'
=> "230 Logged on\n"
irb> ftp.pwd
=> "/"
irb> ftp.chdir 'Inventory'
=> nil
irb> ftp.list 
=> ["-r--r--r-- 1 ftp ftp         302301 Feb 26 20:27 inventory.zip", "-r--r--r-- 1 ftp ftp        1450282 Feb 26 20:24 InventoryWeb.txt"]

...but I'm not sure what conclusion to draw from this? My local version of Ruby? Could it still be a firewall/shell issue?


Solution

  • put: PORT 10,142,96,98,199,111

    You are using FTP in active mode with the private IP address 10.142.96.199. With active mode the server must create a data connection to your host, while with passive mode (PASV command instead of PORT command) the client will connect to the server.

    Since the server is not on the same private network as your host (otherwise you would not be able to connect from a remote system to it) it will not be able to connect to the private IP of 10.142.96.98 given in the PORT command, because private IP addresses can not be accessed from the internet. The server will probably realize this, send some error back and close the connection. Your FTP client will probably try to send another command (like QUIT or ABOR) but since the server has already closed the connection this send will result in EPIPE.

    FileZilla works probably because it will use passive mode instead of active mode. To use passive mode with Net::FTP you have to set ftp.passive = true.