Intermittent FTPS upload failures

Using the :ftp module from erlang I am uploading to an FTPS server running vsFTPd with TLS. It is working but it seemed to have reliability issues. To test it I ran

results = 1..1_000 |> Enum.map(&("testing_#{&1}.txt")) |> Enum.map(fn name ->
	FileTransfer.Ftps.upload("testing text", name, directory, config)
end) |> Enum.reject(fn res ->
	res == :ok
end)

This resulted in a list of 45 elements all containing error: :trans_neg_compl. I’ve been searching around trying to figure out what this error message means but the closest thing I can find is this https://github.com/yrashk/erlang/blob/master/lib/inets/src/ftp/ftp_response.erl which isn’t very helpful (to me at least).

This is what my FileTransfer.Ftps module looks like (Stripped down but same :ftp module function calls).

defmodule FileTransfer.Ftps do
  def upload(content, file_name, dest_dir, config) do
    host = to_charlist(config.host)
    username = to_charlist(config.user)
    password = to_charlist(config.password)

    with {:ok, ftp_client} <- :ftp.open(host, tls: []),
       :ok <- :ftp.user(ftp_client, username, password) do
      file_path = directory |> Path.join(file_name) |> to_charlist()
      :ftp.send_bin(ftp_client, file_content, file_path)
      :ftp.close(ftp_client)
    end
  end
end

If anyone could help me figure out what is going on here it would be appreciated. Without knowing where the :trans_neg_compl message is coming from I don’t know where to start looking for the issue.

1 Like

Hmm well that means the first error number was ‘4’, as in ‘4xx’, do you have the full error code number (log it out or so) as that will tell what the full error is? These error are everything from trying to download a file that doesn’t exist, trying to list a directory that doesn’t exist, trying to upload without permission to do so, etc, etc… :slight_smile:

2 Likes

Hey, sorry for responding so slowly. Haven’t been feeling great the last couple days. I set the :ftp module to ‘verbose’ in the options

    with {:ok, ftp_client} <- :ftp.open(host, tls: [], verbose: true),
         :ok <- :ftp.user(ftp_client, username, password) do
      file_path = directory |> Path.join(file_name) |> to_charlist()
      :ftp.send_bin(ftp_client, file_content, file_path)
      :ftp.close(ftp_client)
    end

and this is the result (With passwords and other identifying information removed

"Receiving: 220 (vsFTPd 3.0.2)"
"Sending: AUTH TLS"
"Receiving: 234 Proceed with negotiation."
"Sending: PBSZ 0"
"Receiving: 200 PBSZ set to 0."
"Sending: PROT P"
"Receiving: 200 PROT now Private."
"Sending: USER <user_name_here>"
"Receiving: 331 Please specify the password."
"Sending: PASS <password_here>"
"Receiving: 230 Login successful."
"Sending: PASV"
"Receiving: 227 Entering Passive Mode (<ip_part>,<ip_part>,<ip_part>,<ip_part>,4,13)."
"Sending: STOR <my/upload/dir/file_1.txt>"
"Receiving: 425 Security: Bad IP connecting."

I’m going to look into the 425 error an see what I can find. I did a quick google search and there was quite a few results for vsFTPd and getting that error. Thank you for pointing me in the right direction on this.

1 Like

Awesome!

Perfect, yep that 425 is the error. That Bad IP connecting implies to me that the server has a whitelist of allowed IP’s to transfer from perhaps? Or maybe some intermediary router or proxy is disallowing it?

1 Like

I don’t know if it is the appropriate way of solving it but I found this post https://www.linuxquestions.org/questions/linux-newbie-8/vsftpd-problem-with-425-security-bad-ip-connecting-120158/ which suggested setting ’ pasv_promiscuous=YES’. http://vsftpd.beasts.org/vsftpd_conf.html suggests against that but this is really just for an end to end testing environment I am setting up. The server is hosted on EC2 so it may be because of their load balancer or something pointing it to the IP that is not configured in ’ pasv_address’ or something. Either way, since it is a test environment I think this solves my problem well enough. I really appreciate the help especially since in the end it turned out to not be erlang/elixir related. Thanks again.

1 Like