vsftpd 响应 PASV 返回 0,0,0,0 [英] vsftpd returns 0,0,0,0 in response to PASV

查看:41
本文介绍了vsftpd 响应 PASV 返回 0,0,0,0的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 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_pasvpostlogin.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 的作者报告这个问题.


保留 PASVEPSV 的原始解释:

只是为了解释 PASVEPSV 之间的区别: 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屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆