http://www.perlmonks.org?node_id=712516

isync has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,
I've been busy setting up a custom server-personality with Net::FTPServer. Everything is running quite well but I've got a strange lingering bug with ACTIVE and PASSIVE connections.

Running linux I have no problems connecting via command-line ftp. Anyway, after the login, for example a "ls" fails with "504 Proxy FTP is not allowed on this server". Of course Proxy FTP is turned off due to security reasons - but as I understand it, I don't need Proxy FTP to just receive a dir listing. (btw turning Proxy FTP on to test if it solves the problem, just resulted in the client infinitely waiting for data.)

I've found out that switching the client into passive mode solves the problem. After that everything works just fine. But this workaround isn't satisfactory as my server can't tell any connecting client to go into passive mode (right?) and this leads to clients like gFTP connecting with default ACTIVE mode to fail on connects. As a note: my server is listening on a port above 1024.

Any hints what I am overseeing here?
  • Comment on Net::FTPServer problem with active/passive connections

Replies are listed 'Best First'.
Re: Net::FTPServer problem with active/passive connections
by missingthepoint (Friar) on Sep 19, 2008 at 14:50 UTC

    To Net::FTPServer, 'proxy ftp' enabled means the server is allowed to connect to any machine in the world. That error message makes me think the server's trying to connect back to an address other than what it thinks is the client address. Is there anything about your setup that would cause this?

    HTH,
    mtp


    email: perl -e 'print reverse map { chr( ord($_)-1 ) } split //, "\x0bufo/hojsfufqAofc";'
      Actually my intuition already was that Net::FTPServer isn't the problem...

      A look into the code of Net::FTPServer revealed that the error is raised by
      if (!$self->{_test_mode} && $hostaddrstring ne $self->{peeraddrstr +ing}) { # See RFC 2577 section 3. $self->reply (504, "Proxy FTP is not allowed on this server.") +; return; }
      so $self->{peeraddrstring} is compared with $hostaddrstring.

      Data::Dumper shows me that $self->{peeraddrstring} correctly holds the IP of my client machine. And $hostaddrstring is constructed from the address my client sends to the ftp-server via the PORT command.

      Here lies the error. As I could see in my gFTP log, gFTP sends: PORT "192,168,xxx,xxx,xxx,xxx"
      And this finally ends up in the $hostaddrstring. But as you can see from the address, this is the local-network-address of my workstation on our LAN here and not my actual public IP. That's why the test in Net::FTPServer fails.

      My FTP client does this all the time and I don't know why other FTP servers never complained. Net::FTPServer seems to be stricter here.

      Anyway, now that we know Net::FTPServer isn't the actual problem. Does anyone know where in my client/workstation/linux-machine setup the flaw is? (as a reminder: if the test would pass, for example by enabling proxy ftp, my ftp-client goes into infinite wait with "150 Opening data connection for file listing.")

        Here lies the error. As I could see in my gFTP log, gFTP sends: PORT "192,168,xxx,xxx,xxx,xxx" And this finally ends up in the $hostaddrstring. But as you can see from the address, this is the local-network-address of my workstation on our LAN here and not my actual public IP. That's why the test in Net::FTPServer fails.

        NAT doesn't work well with clients that are actually servers. FTP in active mode is such a client. When requesting a file (including a directory listing), the server creates a connection to the client over which the data is sent.

        FTP, being a very common protocol, is usually intercepted by NAT and "fixed". Instances of PORT are rewritten from the client's internal address to the router's external address.

        Your problem is that this is not occurring. I can think of three reasons

        • Your NAT software isn't capable of fixing FTP PORT commands. (Not likely)
        • Your NAT software isn't configured to fix FTP PORT commands.
        • Your NAT software doesn't realize your connection is an FTP communication. (Most likely)

        How does NAT know whether a socket is a used as an FTP command connection? Commonly,

        • Any outgoing connection to TCP port 21 is presumed to be an FTP command connection.
        • All other connections are presumed to not be FTP command connections.

        Is your server running on port 21?

        Does anyone know where in my client/workstation/linux-machine setup the flaw is?

        Simply put, you aren't using passive mode. Most FTP clients default to passive mode. That way, all the connections are made from client to server.

        Section 3 of RFC 2577 describes how to mitigate or eliminate bounce attacks for proxy FTP. It recommends specifically against opening a port below 1024 on the remote host at the request of the PORT command. It also allows for disabling the PORT command altogether to prevent that particular form of network abuse. Disabling PORT for a mismatched address is a convenient security workaround.

        The code you quote is, in the latest Net::FTPServer on CPAN anyway, wrapped in a configuration if-block:

        unless ($self->config ("allow proxy ftp")) { if (!$self->{_test_mode} && $hostaddrstring ne $self->{peeraddrstr +ing}) { # See RFC 2577 section 3. $self->reply (504, "Proxy FTP is not allowed on this server.") +; return; } }
        I suggest that if you absolutely need to use the PORT command for FTP which validly appears to the server to be proxy FTP, that you enable 'allow proxy ftp' in the configuration. This is explained in this part of the documentation for the module:
        allow proxy ftp

        Allow proxy FTP. If this is set, then the FTP server can be told to actively connect to addresses and ports on any machine in the world. This is not such a great idea, but required if you follow the RFC very closely. If not set (the default), the FTP server will only connect back to the client machine.

        My preferred suggestion is to fix your NAT so that it handles FTP properly. As a last resort, open your server to attacking every machine on the Internet if you really must. That's what enabling proxy FTP does.

Re: Net::FTPServer problem with active/passive connections
by dwm042 (Priest) on Sep 19, 2008 at 19:56 UTC
    Classically, if you can connect to a FTP server but you cannot do a 'dir', your command channel (port 21 classically) is fine but you're having problems with the data channel (port 20). That your data channel hangs unless people go passive suggests it could be a firewall/networking issue.

    Update: As an example of the kinds of issues FTP generates, you cannot pass FTP traffic through an iptables filter unless you turn on ftp connection tracking.

    More info:

    http://www.proftpd.org/localsite/Userguide/linked/x117.html
Re: Net::FTPServer problem with active/passive connections
by kubrat (Scribe) on Sep 21, 2008 at 11:38 UTC

    Looks like your NAT isn't substituting the local ip in the PORT command with your external ip.

    By the way, your NAT is already doing the ip translation for PASV command, otherwise, PASSIVE mode would not have worked as well.