Question

I am trying to fetch files from a server using FTPS. I'm able to authenticate but when I try to list/fetch the files, I get a "521 Data connections must be encrypted". Is the Net::FTP module capable of this, and how would I accomplish it?

I modified Net::FTPTLS into my own class because I needed to store a self-signed cert.

require 'socket'
require 'openssl'
require 'net/ftp'

module MP
  class FTPS < Net::FTP
    def connect(host, port=FTP_PORT)
      @hostname = host
      super
    end

    def login(user = "anonymous", passwd = nil, cert_file = nil, acct = nil)
      store = OpenSSL::X509::Store.new
      if cert_file == nil
        store.set_default_paths
      else
        certraw = File.read(cert_file)
        cert = OpenSSL::X509::Certificate.new(certraw)
        store.add_cert(cert)
      end
      ctx = OpenSSL::SSL::SSLContext.new('SSLv23')
      ctx.cert_store = store
      ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
      ctx.key = nil
      ctx.cert = cert
      voidcmd("AUTH TLS")
      @sock = OpenSSL::SSL::SSLSocket.new(@sock, ctx)
      @sock.connect
      #@sock.post_connection_check(@hostname)
      super(user, passwd, acct)
      voidcmd("PBSZ 0")
    end
  end
end

And here's the snippet for trying to fetch the files:

def get_ftpclient(host)
  FTPS::new(host)
end

def check_for_files
  @ftp = get_ftpclient(@host)
  @ftp.passive = true
  @ftp.login(@user_name, @password, @cert_file)
  @ftp.chdir(@remote_dir)
  files = @ftp.nlst
  files
end

It fails on the nlst.

Edit: I tried adding voidcmd("PROT P") to the end of the login function but it just hangs for a while, then I eventually get:

IOError: Unsupported record version Unknown-48.48
___BEGIN BACKTRACE___
org/jruby/ext/openssl/SSLSocket.java:564:in `sysread'
/opt/jruby/lib/ruby/gems/1.8/gems/jruby-openssl-0.7.6.1/lib/1.8/openssl/buffering.rb:36:in `fill_rbuff'
/opt/jruby/lib/ruby/gems/1.8/gems/jruby-openssl-0.7.6.1/lib/1.8/openssl/buffering.rb:159:in `eof?'
/opt/jruby/lib/ruby/gems/1.8/gems/jruby-openssl-0.7.6.1/lib/1.8/openssl/buffering.rb:134:in `readline'
/opt/jruby/lib/ruby/1.8/net/ftp.rb:211:in `getline'
    /opt/jruby/lib/ruby/1.8/net/ftp.rb:221:in `getmultiline'
/opt/jruby/lib/ruby/1.8/net/ftp.rb:235:in `getresp'
/opt/jruby/lib/ruby/1.8/net/ftp.rb:251:in `voidresp'
/opt/jruby/lib/ruby/1.8/net/ftp.rb:436:in `retrlines'
/opt/jruby/lib/ruby/1.8/monitor.rb:191:in `mon_synchronize'
/opt/jruby/lib/ruby/1.8/net/ftp.rb:422:in `retrlines'
/opt/jruby/lib/ruby/1.8/net/ftp.rb:612:in `nlst'
... etc
Was it helpful?

Solution

I realize this is an old question, but I stumbled upon it while researching FTPS ruby gems.

No. net::FTP does not, on its own, support FTPS.

I highly recommend double-bag-ftps.

Provides a child class of Net::FTP to support implicit and explicit FTPS.

Version 0.1.1 has been working beautifully for me running daily for the past year.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top