Проблема, с которой я столкнулся, заключается в том, что я получаю ответ «500 Illegal PORT command» от FTP-сервера при попытке загрузить файл программным способом.
Эта программа представляет собой небольшое приложение на C #, которое подключается к FTP-сайту и копирует файлы в каталог по умолчанию. Эта программа работает уже несколько лет, и я уверен, что сам код работает нормально. Я также протестировал приложение, подключившись к моему собственному FTP-сайту с помощью того же приложения, и оно работает. Пассивный режим, похоже, не вариант.
При попытке подключиться к FTP-сайту нашего партнера программа работает должным образом, пока не будет выполнена команда FTP put. При запуске Wireshark я заметил, что исходный IP-адрес моего запроса отличается от IP-адреса, отправляемого командой PORT. Я загрузил сюда изображение захвата (вся конфиденциальная информация была удалена с помощью моего удивительный навыки фотошопа):
.
Я связался с владельцем FTP-сайта, на который мы пытаемся передать файлы, и они открыли свой брандмауэр для нашего нового статического IP-адреса. Я могу подключиться к их сайту с помощью FTP-клиентов с компьютеров на обоих IP-адресах LAN, но эти команды PORT всегда отправляются с использованием того же IP-адреса LAN, что и источник запроса. Я также попытался использовать ftp.exe с сервера, на котором находится программа, и это было успешным (но команда PORT использует тот же IP-адрес, что и источник).
Поэтому я предполагаю, что большой вопрос в том, как я могу контролировать, какой IP-адрес использует команда PORT? Или, если я не могу его контролировать, как программа ftp определяет IP-адрес и ПОРТ?
Оказывается, ответ действительно связан с библиотекой FTP, которую я использовал. Я точно думал, что это не проблема кодирования, но после того, как я понюхал, как библиотека создает запрос, я думаю, что нашел ответ.
Вот соответствующий раздел с использованием ILSpy (я поставил пробел вокруг самой важной строки):
private Socket CreateDataSocketActive()
{
Socket socket = new Socket(2, 1, 6);
IPHostEntry iPHostEntry = Dns.Resolve(Dns.GetHostName());
IPEndPoint iPEndPoint = new IPEndPoint(iPHostEntry.get_AddressList()[0], 0);
socket.Bind(iPEndPoint);
socket.Listen(5);
int port = ((IPEndPoint)socket.get_LocalEndPoint()).get_Port();
IPAddress address = ((IPEndPoint)socket.get_LocalEndPoint()).get_Address();
this.SetDataPort((IPEndPoint)socket.get_LocalEndPoint());
return socket;
}
Похоже, что библиотека создает конечную IP-точку, просто захватывая первый адрес в списке доступных IP-адресов. Для большинства решений это, вероятно, приемлемо, но поскольку на моем сервере несколько сетевых адаптеров, это не работает для меня.
Я знаю, используя FTP.exe, что сервер будет принимать соединения от обеих моих IP-подсетей LAN, если команда PORT выдается с использованием того же IP-адреса LAN, что и источник запроса.
Я предполагаю, что FTP-сервер выполняет какую-то проверку, которая сравнивает два адреса, чтобы убедиться, что они одинаковы. В противном случае я теоретически мог бы передать файл на какое-то другое устройство в совершенно другой сети после входа на FTP-сайт.
Теперь мне нужно найти обходной путь, но это должен быть вопрос поиска новой библиотеки или развертывания моей собственной. Если это поможет кому-то еще, у кого могла быть такая же проблема, я использовал библиотеку com.enterprisedt.net.ftp.