I suspect it might be related with this:
http://code.google.com/p/pyftpdlib/issues/detail?id=123
Could you please try to use the current code from trunk and tell me if
the problem persists?
> I suspect it might be related with this:http://code.google.com/p/pyftpdlib/issues/detail?id=123
> Could you please try to use the current code from trunk and tell me if
> the problem persists?
Forgot to say that I'm already using the last trunk... (r695)
Thanks,
Michele
Then I'm not sure.
Just to be clear: what's going on there is that the client sent a PORT
request to server which is supposed (the server) to connect to IP
1.1.1.1, port ((130 * 256) + 243) which is the address the client is
listening on.
From the server point of view this is nothing but a simple
socket.connect() call (ActiveDTP().__init__() method) .
If connect() doesn't succeed (times out) it could be up to a lot of
things, almost always related with routing problems (e.g. client is
behind a firewall which does not properly forward the incoming PORT
connection, etc...).
I really have no idea why this works with proftpd but not with pyftpdlib.
Are you sure both servers are running using the same configurations?
Are you sure you're using PORT (and not PASV instead) against proftpd as well?
> Forgot to say that I'm already using the last trunk... (r695)
In this specific case trunk differs from a pristine 0.5.2 version
installation in that bind() is called before connect() because of this
recent issue:
http://code.google.com/p/pyftpdlib/issues/detail?id=123
In my previous message I recommended to use the trunk version because
of this, now I'm going to recommend the contrary. =)
Try the "old" 0.5.2 version (which doesn't use bind()) and see if it
solves anything, although I doubt it.
Regards,
Giampaolo
What do you mean with "same configuration"? They cannot share anything
other than the "ftp port" since are both ftp servers... pyftpdlib have
a normal configuration with authentication done by
ftpserver.DummyAuthorizer and proftpd has the default one (no other
done except apt-get install proftpd)
> Are you sure you're using PORT (and not PASV instead) against proftpd as well?
>
I don't know.
I made tests only with the ftp command line installed into my debian
and the tests are done on two different customers (with the
environment above) and both has the same problem.
In all the tests, I tried also to use the "passive" command and the
same problem occurs.
>> Forgot to say that I'm already using the last trunk... (r695)
>
> In this specific case trunk differs from a pristine 0.5.2 version
> installation in that bind() is called before connect() because of this
> recent issue:
> http://code.google.com/p/pyftpdlib/issues/detail?id=123
>
> In my previous message I recommended to use the trunk version because
> of this, now I'm going to recommend the contrary. =)
> Try the "old" 0.5.2 version (which doesn't use bind()) and see if it
> solves anything, although I doubt it.
>
No. Same problem.
If can help you to debug, as said, both my customers have: adsl router
-> fw linux -> server with ftp server and it doesn't work (with
pyftpdlib). On another customer I have: ethernet connection (pppoe
with pubb ip address) -> fw linux -> server with ftp server and here
pyftpdlib works.
So, seeing this, you can tell me that it's the adsl router that create
the problem and I agree with you that it can be but... with proftpd it
works in both cases, so shall be something "inside" pyftpdlib...
Of course, if you need a tcpdump session (for example with both
servers) or something other, ask me without problem!
> Regards,
>
> Giampaolo
>
Thanks,
Michele
I meant "same configuration in respect of active (PORT) connections".
Although pyftpdlib does not provide anything in that sense (ActiveDTP
class just uses bind() than connect() without providing any
"configurable option") maybe proftpd does and has it set by default.
I don't know... I'm just guessing.
> In all the tests, I tried also to use the "passive" command and the
> same problem occurs.
Ok, this is a different problem (PASV vs PORT).
In order to make passive data connections pass through you need to:
- set FTPHandler.masquerade_address to your public IP
- set FTPHandler.passive_ports, which expects a list of ports
(integers) pyftpdlib will use to listen on for passive data transfers
(example: FTPHandler.passive_ports = range(60000, 62000))
- configure the public gateway so that every incoming connection on
one of those ports gets redirected to the private address where the
server listens
There's a FAQ which explains this:
http://code.google.com/p/pyftpdlib/wiki/FAQ#I%27m_behind_a_NAT_/_gateway
In order to make passive connections work on proftpd a similar
configuration must be provided as well.
If PASV works on proftpd but not on pyftpdlib then I guess the first
one is properly configured in a similar manner, while the latter is
not.
> If can help you to debug, as said, both my customers have: adsl router
> -> fw linux -> server with ftp server and it doesn't work (with
> pyftpdlib). On another customer I have: ethernet connection (pppoe
> with pubb ip address) -> fw linux -> server with ftp server and here
> pyftpdlib works.
Ok, but we should first distinguish *what* doesn't work exactly,
whether passive (PASV, aka client connecting to server) or active
(PORT, aka server connecting to client) connections or both as they're
different problems with different solutions.
> So, seeing this, you can tell me that it's the adsl router that create
> the problem and I agree with you that it can be but... with proftpd it
> works in both cases, so shall be something "inside" pyftpdlib...
> Of course, if you need a tcpdump session (for example with both
> servers) or something other, ask me without problem!
Let's focus on the environment which has the problem.
What does not work exactly? PASV or PORT?
In case of PORT check what IP address arrives to the server.
You can do this with TCPDump or by just putting a debugging print in
ActiveDTP class, as such:
class ActiveDTP(asyncore.dispatcher):
def __init__(self, ip, port, cmd_channel):
print ip
...
It might be that the IP address you got in there is a private one
(e.g. 192.168.1.1), pyftpdlib tries to connect() to it and just fails.
The reason why proftpd succeeds might be that after it fails to
connect() to that address it determines the IP of the control
connection (which is supposed to be public, say 151.22.6.45) and tries
that one as a last resort.
But again, I'm just guessing. Such kind of problems are hard to debug
without putting hands on the environment.
Start to answer the questions I've raised, attach further logs if you
think they might help, then let's see where we can go from there.
Giampaolo
I don't know too
>> In all the tests, I tried also to use the "passive" command and the
>> same problem occurs.
>
> Ok, this is a different problem (PASV vs PORT).
> In order to make passive data connections pass through you need to:
>
<-cut->
Sorry, I'm introduced too many problems on the same time...I thought
it would help for understand the problem the tip to talk for the
passive connection, but I think I driven the conversation too many
away from the initial purpose, that was that I'm not able to use
pyftpdlib with active connection, not the passive one!
> So, seeing this, you can tell me that it's the adsl router that create
>> the problem and I agree with you that it can be but... with proftpd it
>> works in both cases, so shall be something "inside" pyftpdlib...
>> Of course, if you need a tcpdump session (for example with both
>> servers) or something other, ask me without problem!
>
> Let's focus on the environment which has the problem.
> What does not work exactly? PASV or PORT?
PORT, so active.
> In case of PORT check what IP address arrives to the server.
> You can do this with TCPDump or by just putting a debugging print in
> ActiveDTP class, as such:
>
> class ActiveDTP(asyncore.dispatcher):
>
> def __init__(self, ip, port, cmd_channel):
> print ip
> ...
>
> It might be that the IP address you got in there is a private one
> (e.g. 192.168.1.1), pyftpdlib tries to connect() to it and just fails.
> The reason why proftpd succeeds might be that after it fails to
> connect() to that address it determines the IP of the control
> connection (which is supposed to be public, say 151.22.6.45) and tries
> that one as a last resort.
>
> But again, I'm just guessing. Such kind of problems are hard to debug
> without putting hands on the environment.
>
This is the server output (client ip 89.202.235.9):
89.202.235.9:49321 <== SYST
89.202.235.9:49321 ==> 215 UNIX Type: L8
89.202.235.9:49321 <== PORT 89,202,235,9,222,96
DEBUG DATA 89.202.235.9 56928 <socket._socketobject object at 0x931b304>
89.202.235.9:49321 ==> 421 Active data channel timed out.
[user]@89.202.235.9:49321 Disconnected.
On client firewall I see the communication thought the port 49321, but
nothing arrive at port 56928
(after about 30 minutes and a lot of tcpdump tests :) ...)
On the client firewall, I tcpdump and compare the two sessions with
proftpd and pyftpdlib and I see that on the proftpd one, after the
PORT command of the client, the server reply with a "200 PORT command
successful" and the client continue with an ack. After starts with the
LIST command and continue...
On the pyftpdlib session this doesn't happen: client ask for the PORT
and server reply with an ack, after all stall for about 30 seconds and
continue with the timeout.
> Start to answer the questions I've raised, attach further logs if you
> think they might help, then let's see where we can go from there.
>
>
Hope that this " simplified dump" can help.
Michele
> On client firewall I see the communication thought the port 49321, but
> nothing arrive at port 56928
> (after about 30 minutes and a lot of tcpdump tests :) ...)
Are you saying that server is trying to connect to port 49321instead of 56928?
> (after about 30 minutes and a lot of tcpdump tests :) ...)
>
> On the client firewall, I tcpdump and compare the two sessions with
> proftpd and pyftpdlib and I see that on the proftpd one, after the
> PORT command of the client, the server reply with a "200 PORT command
> successful" and the client continue with an ack. After starts with the
> LIST command and continue...
> On the pyftpdlib session this doesn't happen: client ask for the PORT
> and server reply with an ack, after all stall for about 30 seconds and
> continue with the timeout.
Unfortunately that doesn't help much.
proftpd responds with 200 because a connection took place *first*.
The problem with pyftpdlib is that doesn't happen.
connect() doesn't connect hence 200 isn't obviously sent.
Since we're talking about active (PORT) connections the problem is
probably the client firewall which doesn't properly forward port
56928.
As to why such connection passes through by using proftpd I really have no idea.
I'm not aware of any "magic" you can do against the server socket
which calls connect() aside from calling bind() first, which latest
revision of pyftpdlib already does.
Could you please try to run the following script against both proftpd
and pyftpdlib and paste the results?
import ftplib, socket
ftp = ftplib.FTP(timeout=3)
ftp.connect(host='localhost', port=21)
ftp.login()
# passive
ftp.set_pasv(True)
host, port = ftp.makepasv()
conn = socket.create_connection((host, port), timeout=3)
print "passive: local:%s remote:%s" %(conn.getsockname(), conn.getpeername())
# active
ftp.set_pasv(False)
listening_sock = ftp.makeport()
print "active: local:" + str(listening_sock.getsockname())
conn = listening_sock.accept()[0]
print "active: local:%s remote:%s" %(conn.getsockname(), conn.getpeername())