🐞 fix(ftpserver): 修改被动模式端口号的分配方式

添加端口号区间,设置可重复绑定属性,使得端口号可控
This commit is contained in:
huheng@kylinos.cn 2022-11-08 14:02:54 +08:00
parent 2aa1c499d1
commit e5ff70b22a
2 changed files with 77 additions and 32 deletions

View File

@ -6,6 +6,7 @@
#include <map>
#include <functional>
#include <fstream>
#include <unistd.h>
#include "filesystem.h"
@ -13,6 +14,21 @@ namespace fineftp
{
const std::string DEVICEID_FILE_LOACLPATH = getenv("HOME") + std::string("/.connectivitycache/DeviceId");
const int MAX_PORT_NUM = 6;
const unsigned short INITIAL_PORT = 27193;
std::queue<unsigned short> FtpSession::s_freePorts = FtpSession::initPortQueue();
std::queue<unsigned short> FtpSession::initPortQueue()
{
std::queue<unsigned short> freePorts;
for (int i = 0; i < MAX_PORT_NUM; i++) {
freePorts.push(INITIAL_PORT + i);
}
return freePorts;
}
FtpSession::FtpSession(asio::io_service &io_service, const UserDatabase &user_database,
const std::function<void()> &completion_handler)
@ -313,39 +329,56 @@ void FtpSession::handleFtpCommandPASV(const std::string & /*param*/)
}
}
asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), 0);
{
asio::error_code ec;
data_acceptor_.open(endpoint.protocol(), ec);
if (ec) {
std::cerr << "Error opening data acceptor: " << ec.message() << std::endl;
sendFtpMessage(FtpReplyCode::SERVICE_NOT_AVAILABLE, "Failed to enter passive mode.");
return;
}
}
{
asio::error_code ec;
data_acceptor_.bind(endpoint);
if (ec) {
std::cerr << "Error binding data acceptor: " << ec.message() << std::endl;
sendFtpMessage(FtpReplyCode::SERVICE_NOT_AVAILABLE, "Failed to enter passive mode.");
return;
}
}
{
asio::error_code ec;
data_acceptor_.listen(asio::socket_base::max_connections, ec);
if (ec) {
std::cerr << "Error listening on data acceptor: " << ec.message() << std::endl;
sendFtpMessage(FtpReplyCode::SERVICE_NOT_AVAILABLE, "Failed to enter passive mode.");
return;
if (!s_freePorts.empty()) {
m_currentPort = s_freePorts.front();
s_freePorts.pop();
try {
asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), m_currentPort);
{
asio::error_code ec;
data_acceptor_.open(endpoint.protocol(), ec);
if (ec) {
std::cerr << "Error opening data acceptor: " << ec.message() << std::endl;
sendFtpMessage(FtpReplyCode::SERVICE_NOT_AVAILABLE, "Failed to enter passive mode.");
return;
}
}
data_acceptor_.set_option(asio::ip::tcp::acceptor::reuse_address(true));
{
asio::error_code ec;
data_acceptor_.bind(endpoint);
if (ec) {
std::cerr << "Error binding data acceptor: " << ec.message() << std::endl;
sendFtpMessage(FtpReplyCode::SERVICE_NOT_AVAILABLE, "Failed to enter passive mode.");
return;
}
}
{
asio::error_code ec;
data_acceptor_.listen(asio::socket_base::max_connections, ec);
if (ec) {
std::cerr << "Error listening on data acceptor: " << ec.message() << std::endl;
sendFtpMessage(FtpReplyCode::SERVICE_NOT_AVAILABLE, "Failed to enter passive mode.");
return;
}
}
} catch (std::exception &_e) {
#ifndef NDEBUG
std::cout << _e.what() << std::endl;
#endif
s_freePorts.push(m_currentPort);
handleFtpCommandPASV("PASV");
}
} else {
#ifndef NDEBUG
std::cerr << "More than the maximum number of ports that can be allocated." << std::endl;
#endif
return;
}
// Split address and port into bytes and get the port the OS chose for us
auto ip_bytes = command_socket_.local_endpoint().address().to_v4().to_bytes();
auto port = data_acceptor_.local_endpoint().port();
// auto port = data_acceptor_.local_endpoint().port();
std::ifstream file;
@ -356,8 +389,8 @@ void FtpSession::handleFtpCommandPASV(const std::string & /*param*/)
getline(file, deviceId);
std::cout << deviceId << std::endl;
if (!deviceId.empty()) {
std::string common = std::string("adb -s ") + deviceId + std::string(" reverse tcp:") + std::to_string(port)
+ std::string(" tcp:") + std::to_string(port);
std::string common = std::string("adb -s ") + deviceId + std::string(" reverse tcp:")
+ std::to_string(m_currentPort) + std::string(" tcp:") + std::to_string(m_currentPort);
system(common.c_str());
}
}
@ -369,9 +402,10 @@ void FtpSession::handleFtpCommandPASV(const std::string & /*param*/)
for (size_t i = 0; i < 4; i++) {
stream << static_cast<int>(ip_bytes[i]) << ",";
}
stream << ((port >> 8) & 0xff) << "," << (port & 0xff) << ")";
stream << ((m_currentPort >> 8) & 0xff) << "," << (m_currentPort & 0xff) << ")";
sendFtpMessage(FtpReplyCode::ENTERING_PASSIVE_MODE, "Entering passive mode " + stream.str());
return;
} // namespace fineftp
@ -1053,7 +1087,8 @@ void FtpSession::addDataToBufferAndSend(std::shared_ptr<std::vector<char>> data,
void FtpSession::writeDataToSocket(std::shared_ptr<asio::ip::tcp::socket> data_socket,
std::function<void(void)> fetch_more)
{
data_buffer_strand_.post([me = shared_from_this(), data_socket, fetch_more]() {
auto port = m_currentPort;
data_buffer_strand_.post([me = shared_from_this(), data_socket, fetch_more, port]() {
auto data = me->data_buffer_.front();
if (data) {
@ -1078,6 +1113,9 @@ void FtpSession::writeDataToSocket(std::shared_ptr<asio::ip::tcp::socket> data_s
// we got to the end of transmission
me->data_buffer_.pop_front();
me->sendFtpMessage(FtpReplyCode::CLOSING_DATA_CONNECTION, "Done");
s_freePorts.push(port);
data_socket->close();
// delete data_socket;
}
});
}

View File

@ -3,6 +3,7 @@
#include <asio.hpp>
#include <deque>
#include <queue>
#include <fstream>
#include "ftp_message.h"
@ -59,6 +60,8 @@ private:
void handleFtpCommand(const std::string &command);
static std::queue<unsigned short> initPortQueue();
////////////////////////////////////////////////////////
// FTP Commands
////////////////////////////////////////////////////////
@ -199,5 +202,9 @@ private:
// Current state
std::string ftp_working_directory_;
unsigned short m_currentPort;
static std::queue<unsigned short> s_freePorts;
};
} // namespace fineftp