vsftpd 响应 PASV 返回 0,0,0,0 [英] vsftpd returns 0,0,0,0 in response to PASV
问题描述
我在 AWS EC2 (Ubuntu16.04) 上使用被动模式 (PASV
) 设置了 FTP 服务器,但它不起作用.但是,它适用于 EPSV
,不知道为什么.我四处搜索但没有找到答案,有没有人可以帮我解决这个问题?
1.vsftpd 配置
anonymous_enable=NOlocal_enable=是写启用=是chroot_local_user=是pasv_enable=是pasv_min_port=13000pasv_max_port=13100端口启用=是pasv_address=[AWS EC2 实例的公网地址]allow_writeable_chroot=是seccomp_sandbox=否
2.AWS EC2 防火墙
3.通过 FireFTP 测试
在PASV
模式下,我无法连接到FTP服务器,日志为:
220 (vsFTPd 3.0.3)用户传感器331 请指定密码.PASS(密码未显示)230 登录成功.CWD/250 目录更改成功.A型200 切换到 ASCII 模式.PASV退出
然而,它与 EPSV
一起工作(选中 IPV6 复选框),日志如下:
220 (vsFTPd 3.0.3)用户传感器331 请指定密码.PASS(密码未显示)230 登录成功.残疾人士257 /"是当前目录A型200 切换到 ASCII 模式.EPSV229 进入扩展被动模式(|||13082|)列表150 目录列表来了.226 目录发送正常.
4.通过Python ftplib测试
from ftplib import FTP内容 = []ftp = FTP(主机=xxx,超时=3000)ftp.login(user=xxx, passwd=xxx)ftp.set_debuglevel(2)ftp.retrlines("NLST", contents.append)ftp.退出()
日志如下:
*cmd* 'TYPE A'*put* 'TYPE A
'*get* '200 切换到 ASCII 模式.
'*resp* '200 切换到 ASCII 模式.'*cmd* 'PASV'*put* 'PASV
'*get* '227 进入被动模式 (0,0,0,0,50,245).
'*resp* '227 进入被动模式 (0,0,0,0,50,245).'ConnectionRefusedError: [Errno 111] 连接被拒绝
在我看来,这像是 vsftpd 中的一个错误.
从代码看起来,它总是发送0,0,0,0
,如果设置了公共pasv_address
,但服务器有一个(本地)IPv6 地址.
要解决此问题,请确保服务器不侦听 IPv6 地址(默认行为是什么,您可以通过设置 listen_ipv6=YES
覆盖):
listen_ipv6=NO听=是
唯一的其他解决方案是删除私有 IPv6 地址(如果在 EC2 中可能的话).
或者使用其他 FTP 服务器,例如ProFTPD.
或者让ftplib忽略服务器返回的IP地址.
请参阅无法使用 ftplib 列出 FTP 目录 - 但 FTP 客户端可以工作
为了证明这确实是一个错误,请检查最新的 vsftpd 版本(3.0.3)的代码:
handle_pasv
在 postlogin.c
中:
int is_ipv6 = vsf_sysutil_sockaddr_is_ipv6(p_sess->p_local_addr);...如果(tunable_pasv_address != 0){vsf_sysutil_sockaddr_alloc_ipv4(&s_p_sockaddr);/* 报告配置中指定的被动地址 */如果(vsf_sysutil_inet_aton(tunable_pasv_address,s_p_sockaddr)== 0){死(无效的 pasv_address");}}别的{vsf_sysutil_sockaddr_clone(&s_p_sockaddr, p_sess->p_local_addr);}str_alloc_text(&s_pasv_res_str, "进入被动模式(");如果(!is_ipv6){str_append_text(&s_pasv_res_str, vsf_sysutil_inet_ntop(s_p_sockaddr));}别的{const void* p_v4addr = vsf_sysutil_sockaddr_ipv6_v4(s_p_sockaddr);如果(p_v4addr){str_append_text(&s_pasv_res_str, vsf_sysutil_inet_ntoa(p_v4addr));}别的{str_append_text(&s_pasv_res_str, "0,0,0,0");}}
其中 vsf_sysutil_sockaddr_ipv6_v4
返回 0,如果 s_p_sockaddr
不是 IPv6,则在设置 pasv_address
时它永远不会是.>
sysutil.c
:
const void*vsf_sysutil_sockaddr_ipv6_v4(const struct vsf_sysutil_sockaddr* p_addr){静态无符号字符模式[12] ={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF };const unsigned char* p_addr_start;如果(p_addr->u.u_sockaddr.sa_family != AF_INET6){返回0;}if (vsf_sysutil_memcmp(pattern, &p_addr->u.u_sockaddr_in6.sin6_addr, 12)){返回0;}p_addr_start = (const unsigned char*)&p_addr->u.u_sockaddr_in6.sin6_addr;返回 &p_addr_start[12];}
恕我直言,代码错了.当 IP 地址被自动检测"时,它可以工作(并且有意义).来自 p_sess->p_local_addr
,但在使用 pasv_address
地址时失败.
考虑向 vsftpd 的作者报告这个问题.
保留 PASV
与 EPSV
的原始解释:
只是为了解释 PASV
和 EPSV
之间的区别: PASV
在响应中返回一个 IP 地址.该信息有 99.9% 的冗余.当服务器不知道其外部 IP 地址时,它通常会导致问题.
EPSV
的引入晚于 PASV
,当时很明显响应中的 IP 地址存在问题.所以对于 EPSV
,只包含一个端口号.并且客户端隐式连接到FTP服务器IP地址.
如果服务器在响应 PASV
命令时确实返回了 0,0,0,0
,很明显为什么客户端无法连接到服务器,当使用PASV
.
I set up an FTP server on AWS EC2 (Ubuntu16.04) with passive mode (PASV
), but it doesn't work. However, it works with EPSV
, don't know why. I searched around but find no answers, any body can help me with this?
1. vsftpd config
anonymous_enable=NO
local_enable=YES
write_enable=YES
chroot_local_user=YES
pasv_enable=YES
pasv_min_port=13000
pasv_max_port=13100
port_enable=YES
pasv_address=[public ip address of AWS EC2 instance]
allow_writeable_chroot=YES
seccomp_sandbox=NO
2. AWS EC2 Firewall
3. Test through FireFTP
With PASV
mode, I cannot connect to FTP server, the log is:
220 (vsFTPd 3.0.3)
USER sensor
331 Please specify the password.
PASS (password not shown)
230 Login successful.
CWD /
250 Directory successfully changed.
TYPE A
200 Switching to ASCII mode.
PASV
QUIT
However, with it works with EPSV
(with IPV6 checkbox selected), the log as below:
220 (vsFTPd 3.0.3)
USER sensor
331 Please specify the password.
PASS (password not shown)
230 Login successful.
PWD
257 "/" is the current directory
TYPE A
200 Switching to ASCII mode.
EPSV
229 Entering Extended Passive Mode (|||13082|)
LIST
150 Here comes the directory listing.
226 Directory send OK.
4. Test through Python ftplib
from ftplib import FTP
contents = []
ftp = FTP(host=xxx, timeout=3000)
ftp.login(user=xxx, passwd=xxx)
ftp.set_debuglevel(2)
ftp.retrlines("NLST", contents.append)
ftp.quit()
The log as below:
*cmd* 'TYPE A'
*put* 'TYPE A
'
*get* '200 Switching to ASCII mode.
'
*resp* '200 Switching to ASCII mode.'
*cmd* 'PASV'
*put* 'PASV
'
*get* '227 Entering Passive Mode (0,0,0,0,50,245).
'
*resp* '227 Entering Passive Mode (0,0,0,0,50,245).'
ConnectionRefusedError: [Errno 111] Connection refused
It looks like a bug in vsftpd to me.
From the code it looks like, it will always sends the 0,0,0,0
, if the public pasv_address
is set, but the server has a (local) IPv6 address.
To fix this, make sure the server does not listen on IPv6 address (what is the default behavior, which you are overriding by setting listen_ipv6=YES
):
listen_ipv6=NO
listen=YES
The only other solution is removing a private IPv6 address, if it is possible in EC2.
Or use another FTP server, e.g. ProFTPD.
Or make ftplib ignore the IP address returned by the server.
See Cannot list FTP directory using ftplib – but FTP client works
To prove that this is indeed a bug, check this code of the latest vsftpd release (3.0.3):
handle_pasv
in postlogin.c
:
int is_ipv6 = vsf_sysutil_sockaddr_is_ipv6(p_sess->p_local_addr);
...
if (tunable_pasv_address != 0)
{
vsf_sysutil_sockaddr_alloc_ipv4(&s_p_sockaddr);
/* Report passive address as specified in configuration */
if (vsf_sysutil_inet_aton(tunable_pasv_address, s_p_sockaddr) == 0)
{
die("invalid pasv_address");
}
}
else
{
vsf_sysutil_sockaddr_clone(&s_p_sockaddr, p_sess->p_local_addr);
}
str_alloc_text(&s_pasv_res_str, "Entering Passive Mode (");
if (!is_ipv6)
{
str_append_text(&s_pasv_res_str, vsf_sysutil_inet_ntop(s_p_sockaddr));
}
else
{
const void* p_v4addr = vsf_sysutil_sockaddr_ipv6_v4(s_p_sockaddr);
if (p_v4addr)
{
str_append_text(&s_pasv_res_str, vsf_sysutil_inet_ntoa(p_v4addr));
}
else
{
str_append_text(&s_pasv_res_str, "0,0,0,0");
}
}
where the vsf_sysutil_sockaddr_ipv6_v4
returns 0, if the s_p_sockaddr
is not IPv6, what it never is, when the pasv_address
is set.
sysutil.c
:
const void*
vsf_sysutil_sockaddr_ipv6_v4(const struct vsf_sysutil_sockaddr* p_addr)
{
static unsigned char pattern[12] =
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF };
const unsigned char* p_addr_start;
if (p_addr->u.u_sockaddr.sa_family != AF_INET6)
{
return 0;
}
if (vsf_sysutil_memcmp(pattern, &p_addr->u.u_sockaddr_in6.sin6_addr, 12))
{
return 0;
}
p_addr_start = (const unsigned char*)&p_addr->u.u_sockaddr_in6.sin6_addr;
return &p_addr_start[12];
}
Imho, the code is wrong. It works (and makes sense), when the IP address is "autodetected" from p_sess->p_local_addr
, but fails, when the pasv_address
address is used.
Consider reporting this to the author of vsftpd.
Keeping an original explanation of the PASV
vs. EPSV
:
Just to explain the difference between the PASV
and the EPSV
: The PASV
returns an IP address in the response. That information is in 99.9% redundant. And it commonly causes problems, when the server is not aware of its external IP address.
The EPSV
was introduced later than the PASV
, when it was clear that the IP address presence in the response is problematic. So with the EPSV
, only a port number is included. And the client connects to the FTP server IP address implicitly.
If the server really returns 0,0,0,0
in a response to the PASV
command, it's clear why the client cannot connect to the server, when the PASV
is used.
这篇关于vsftpd 响应 PASV 返回 0,0,0,0的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!