pyftpdlib behind nat config script

541 views
Skip to first unread message

luismanolo

unread,
Jun 2, 2010, 3:24:41 AM6/2/10
to Python FTP server library - Discussion group
First, sorry about my english:

Thats the script to run my pyftpdlib server, and the server respond
"550 permission denied":



#!/usr/bin/env python



"""A basic FTP server which uses a DummyAuthorizer for managing
'virtual

users', setting a limit for incoming connections.

"""



import os

import urllib2

from pyftpdlib import ftpserver



def main():

# I get the external Ip of my server behind the router
ext_ip = urllib2.urlopen("http://whatismyip.org").read()

# Instantiate a dummy authorizer for managing 'virtual' users

authorizer = ftpserver.DummyAuthorizer()



# Define a new user having full r/w permissions and a read-only

# anonymous user

authorizer.add_user('user', 'password', '/home/user/ftpserver',
perm='elradfmw')



# Instantiate FTP handler class

ftp_handler = ftpserver.FTPHandler

ftp_handler.authorizer = authorizer



# Define a customized banner (string returned when client connects)

ftp_handler.banner = "Servidor ftp basado en pyftpdlib, ver:%s "
%ftpserver.__ver__



# Specify a masquerade address and the range of ports to use for

# passive connections. Decomment in case you're behind a NAT.

#ftp_handler.masquerade_address = '151.25.42.11'

# I test with this solution:
#ftp_handler.masquerade_address = {'192.168.1.12':ext_ip}

# but finally I use this one:
ftp_handler.masquerade_address = ext_ip

# I redirect on my router the port 60001 ( and 2121 of
course).
ftp_handler.passive_ports = range(60001, 65535)



# Instantiate FTP server class and listen to 192.168.1.12:21
21
address = ('192.168.1.12', 2121)

ftpd = ftpserver.FTPServer(address, ftp_handler)



# set a limit for connections

ftpd.max_cons = 256

ftpd.max_cons_per_ip = 5



# start ftp server

ftpd.serve_forever()



if __name__ == '__main__':

main()


The server works right on local mode...

Many thanks.

Giampaolo Rodola'

unread,
Jun 2, 2010, 2:30:05 PM6/2/10
to Python FTP server library - Discussion group
Hi,
unfortunately you didn't give enough information.
When do you get "550 permission denied" exactly?
It can be returned in many circumstances.

luismanolo

unread,
Jun 3, 2010, 2:47:02 AM6/3/10
to pyft...@googlegroups.com
The complete log is:

--- my translation from spanish  ;) --
"Failure the authentication in the server: 550 Permission denied"

there is a problem with my NAT config, because in "localhost" mode works fine.

Thanks again.

2010/6/2 Giampaolo Rodola' <g.ro...@gmail.com>

--
You received this message because you are subscribed to the "Python FTP server library" project group:
http://code.google.com/p/pyftpdlib/
To post to this group, send email to pyft...@googlegroups.com
To unsubscribe from this group, send email to pyftpdlib-...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/pyftpdlib



--
http://vimeo.com/luismanolo
http://youtube.es/luismanolo
http://delasonsierra.blogspot.com
http://www.logrobomberos.com

Jay Loden

unread,
Jun 3, 2010, 9:43:10 AM6/3/10
to pyft...@googlegroups.com
Hi Luis, 

I think Giampaolo was actually asking if you can include the entire log from the session so we can see the message before and after the 550 error is received. That will help us determine where the problem is occurring. For example, if we were troubleshooting an authentication error: 

[]127.0.0.1:61201 Connected.
127.0.0.1:61201 ==> 220 pyftpdlib 0.5.2 based ftpd ready.
127.0.0.1:61201 <== USER anoynmous
127.0.0.1:61201 ==> 331 Username ok, send password.
127.0.0.1:61201 <== PASS ******
127.0.0.1:61201 ==> 530 Authentication failed.
[]@127.0.0.1:61201 Authentication failed.

That way we have more details and information to work with besides just the exact error message. 

Regards,

-Jay

luismanolo

unread,
Jun 4, 2010, 3:06:47 AM6/4/10
to pyft...@googlegroups.com
Sorry:

the log of the pyftpdlib server is only:
Serving FTP on 192.168.1.12:2121

But the log of the ftp client is:
220 DrayTek FTP version 1.0
       USER geofoc
331 Enter PASS command
       PASS (password not shown)
550 Permission denied
Unable to make a connection. Please try again.

"DrayTek" is my router!!


And the port redirection on my router is:
External port:     IP:                     Internal port:
2121                 192.168.1.12       2121
60001               192.168.1.12       60001
(masquerade_address = ext_ip     #the external ip of my router)
(passive_ports = range(60001, 60001)     #the ports open for passive conections)

I think:  the external passive conections dont go to the server, but yes to the router..

Sorrry about my english again...;)


2010/6/3 Jay Loden <jlo...@gmail.com>

Yan Raber

unread,
Jun 4, 2010, 4:40:37 AM6/4/10
to Python FTP server library - Discussion group
Hi Luis,
the client is actually connecting to the FTP server embedded in your
router (port 21) not to your internal server (port 2121).
Are you sure you are really connecting to port 2121? Have you
configured your client properly?


On 4 Giu, 09:06, luismanolo <luisman...@gmail.com> wrote:
> Sorry:
>
> the log of the pyftpdlib server is only:
> *Serving FTP on 192.168.1.12:2121*
>
> But the log of the ftp client is:*
> *
> *220 DrayTek FTP version 1.0*
> *       USER geofoc*
> *331 Enter PASS command*
> *       PASS (password not shown)*
> *550 Permission denied
> *
> *Unable to make a connection. Please try again.*
>
> "DrayTek" is my router!!
>
> And the port redirection on my router is:
> *External port:     IP:                     Internal port:
> 2121                 192.168.1.12       2121
> 60001               192.168.1.12       60001
> (masquerade_address = ext_ip     #the external ip of my router)
> (passive_ports = range(60001, 60001)     #the ports open for passive
> conections)
> *
> I think:  the external passive conections dont go to the server, but yes to
> the router..
>
> Sorrry about my english again...;)
>
> 2010/6/3 Jay Loden <jlo...@gmail.com>
>
>
>
>
>
> > Hi Luis,
>
> > I think Giampaolo was actually asking if you can include the entire log
> > from the session so we can see the message before and after the 550 error is
> > received. That will help us determine where the problem is occurring. For
> > example, if we were troubleshooting an authentication error:
>
> > []127.0.0.1:61201 Connected.
> > 127.0.0.1:61201 ==> 220 pyftpdlib 0.5.2 based ftpd ready.
> > 127.0.0.1:61201 <== USER anoynmous
> > 127.0.0.1:61201 ==> 331 Username ok, send password.
> > 127.0.0.1:61201 <== PASS ******
> > 127.0.0.1:61201 ==> 530 Authentication failed.
> > []@127.0.0.1:61201 Authentication failed.
>
> > That way we have more details and information to work with besides just the
> > exact error message.
>
> > Regards,
>
> > -Jay
>
> > On Thu, Jun 3, 2010 at 2:47 AM, luismanolo <luisman...@gmail.com> wrote:
>
> >> The complete log is:
>
> >> --- my translation from spanish  ;) --
> >> *"Failure the authentication in the server: 550 Permission denied"*
>
> >> there is a problem with my NAT config, because in "localhost" mode works
> >> fine.
>
> >> Thanks again.
>
> >> 2010/6/2 Giampaolo Rodola' <g.rod...@gmail.com>

luismanolo

unread,
Jun 4, 2010, 7:22:57 AM6/4/10
to pyft...@googlegroups.com
[NOT SOLVED]:
I change the port to 2120 (sorry, my ftp port for the router was 2121) and show the following error:

421 Passive data channel timed out.
: //


My script are now:

"""
    Un servidor ftp basico basado en pyftpdlib
"""
 
import os
import time
from socket import gethostbyname
from pyftpdlib import ftpserver
 
now = lambda: time.strftime("[%Y-%b-%d %H:%M:%S]")
 
f1 = open('ftpd.log', 'a')
f2 = open('ftpd.lines.log', 'a')
def standard_logger(msg):
    f1.write("%s %s\n" %(now(), msg))
 
def line_logger(msg):
    f2.write("%s %s\n" %(now(), msg))
 
def main():
    ftpserver.log = standard_logger
    ftpserver.logline = line_logger
 
    authorizer = ftpserver.DummyAuthorizer()
    authorizer.add_user('geofoc', 'geobartolo', '/home/geofoc/prodjango/geofoc', perm='elradfmw')
 
    ftp_handler = ftpserver.FTPHandler
    ftp_handler.authorizer = authorizer
 
    ftp_handler.banner = "Servidor ftp basado en pyftpdlib, ver:%s " %ftpserver.__ver__
 
    ext_ip = gethostbyname('geofoc.sytes.net')
    print "IP externa: " + ext_ip

    #ftp_handler.masquerade_address = {'192.168.1.12':ext_ip}
    ftp_handler.masquerade_address = ext_ip
    ftp_handler.passive_ports = range(60001, 60001)
 
    address = ('192.168.1.12', 2120)
    ftpd = ftpserver.FTPServer(address, ftp_handler)
 
    ftpd.max_cons = 256
    ftpd.max_cons_per_ip = 5
 
    ftpd.serve_forever()
 
if __name__ == '__main__':
    main()

Many thanks again....


2010/6/4 Yan Raber <yanr...@gmail.com>

luismanolo

unread,
Jun 4, 2010, 7:43:11 AM6/4/10
to pyft...@googlegroups.com
Sorry, my server log is...


Serving FTP on 192.168.1.12:2120
[]89.128.128.217:49185 Connected.
89.128.128.217:49185 ==> 220 Servidor ftp basado en pyftpdlib, ver:0.5.2
89.128.128.217:49185 <== FEAT
89.128.128.217:49185 ==> 211 End FEAT.
89.128.128.217:49185 <== OPTS MLST type;perm;size;modify;unix.mode;unix.uid;unix.gid;
89.128.128.217:49185 ==> 530 Log in with USER and PASS first.
89.128.128.217:49185 <== USER geofoc
89.128.128.217:49185 ==> 331 Username ok, send password.
89.128.128.217:49185 <== PASS ******
89.128.128.217:49185 ==> 230 Login successful.
[geofoc]@89.128.128.217:49185 User geofoc logged in.
89.128.128.217:49185 <== PWD
89.128.128.217:49185 ==> 257 "/" is the current directory.
89.128.128.217:49185 <== PASV
89.128.128.217:49185 ==> 227 Entering passive mode (212,21,229,186,251,165).
89.128.128.217:49185 <== LIST
[geofoc]@89.128.128.217:49185 OK LIST "/". Transfer starting.
89.128.128.217:49185 ==> 150 File status okay. About to open data connection.
89.128.128.217:49185 <== ����ABOR
89.128.128.217:49185 ==> 225 ABOR command successful; data channel closed.
[geofoc]@89.128.128.217:49185 Disconnected.



Thanks again...


2010/6/4 luismanolo <luism...@gmail.com>

Giampaolo Rodola'

unread,
Jun 4, 2010, 2:35:06 PM6/4/10
to Python FTP server library - Discussion group
I still don't get what does not work exactly.
The file transfer?

By looking at how you configured your server I notice some strange
things.

>>> ext_ip = gethostbyname('geofoc.sytes.net')
>>> ftp_handler.masquerade_address = ext_ip

Here you're setting the masquerade address of geofoc.sytes.net.
Is that you?
The masquerade_address you are supposed to set should be the same you
see here:
http://www.whatsmyip.org/

If "geofoc.sytes.net" IP address is the same you see there then that's
fine.

>>> ftp_handler.passive_ports = range(60001, 60001)

This is wrong as you're setting an empty range of ports.
This causes the server to use kernel-assigned random ports for passive
connections.

In order to configure your server to accept passive connections you
need to:

- specify a valid external address (e.g. FTPHandler.masquerade_address
= "152.1.2.3") where by "valid" I mean, for example, the address of
your router
- specify a range of ports (e.g. FTPHandler.passive_ports =
range(60000, 61000))
- configure your NAT so that the incoming connections to 152.1.2.3 on
a port between 60000 and 61000 gets redirected to the private IP
address your server listens on

Take a look a this FAQ: http://code.google.com/p/pyftpdlib/wiki/FAQ#I%27m_behind_a_NAT_/_gateway

Also by looking at this message:

*421 Passive data channel timed out."

...it's very likely that you haven't satisfied all the 3 points above.



Regards,

Giampaolo

luismanolo

unread,
Jun 6, 2010, 3:03:59 PM6/6/10
to pyft...@googlegroups.com
[SOLVED]
The problem was that I don't open ALL of the passive ports range(60000, 61000) on my router, the final script is:

#!/usr/bin/env python

"""
Un servidor ftp basico basado en pyftpdlib
"""

import os
import time
import csv
from socket import gethostbyname
from pyftpdlib import ftpserver

now = lambda: time.strftime("[%Y-%b-%d %H:%M:%S]")

f1 = open('ftpd.log', 'a')
f2 = open('ftpd.lines.log', 'a')
def standard_logger(msg):
f1.write("%s %s\n" %(now(), msg))

def line_logger(msg):
f2.write("%s %s\n" %(now(), msg))

def main():
        # csv files with "user,passwd,dir,perm"
archivo = "usuarios.csv"
ftpserver.log = standard_logger
ftpserver.logline = line_logger

authorizer = ftpserver.DummyAuthorizer()

reader = csv.reader(open(archivo, 'rb'))
for index,row in enumerate(reader):
if row[0][:1] != "#":
authorizer.add_user(row[0], row[1], row[2], perm=row[3])

ftp_handler = ftpserver.FTPHandler
ftp_handler.authorizer = authorizer

ftp_handler.banner = "Servidor ftp basado en pyftpdlib, ver:%s " %ftpserver.__ver__

ext_ip = gethostbyname('midominio.sytes.net')
print "IP externa: " + ext_ip
ftp_handler.masquerade_address = ext_ip
ftp_handler.passive_ports = range(60000, 61000)

address = ('192.168.1.12', 2120)
ftpd = ftpserver.FTPServer(address, ftp_handler)

ftpd.max_cons = 256
ftpd.max_cons_per_ip = 5

ftpd.serve_forever()

if __name__ == '__main__':
    main()


Many thanks again from Spain.....

2010/6/4 Giampaolo Rodola' <g.ro...@gmail.com>

--
You received this message because you are subscribed to the "Python FTP server library" project group:
http://code.google.com/p/pyftpdlib/
To post to this group, send email to pyft...@googlegroups.com
To unsubscribe from this group, send email to pyftpdlib-...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/pyftpdlib
Reply all
Reply to author
Forward
0 new messages