I can't figure this problem out I'm having at a client's site. The client has two sites and both run the same version of my app. At one site there are no problems but at the other I started to consistently get the following error when trying to download files from a FTP site:
"227 Entering Passive Mode (...)"
I've been reading on SO and Google and cannot figure out the problem. I want to drop this client because they are just costing money. I'm using the FTP functionality included in .NET 3.5.
Any clue as to what could be going on?? Network security changes on their end?
Test with a client ftp but only in ACTIVE MODE.
Deactivate this:
in Tools - internet options - advanced -
"Use passive FTP (for firewall and DSL modem )"
To avoid that error, just use reqFTP.UsePassive = false;
reqFTP.UsePassive = false;
Check below
FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create("ftp://127.0.0.1/1542");
ftpRequest.Credentials = new NetworkCredential("6584", "123456");
ftpRequest.Method = WebRequestMethods.Ftp.ListDirectory;
ftpRequest.UsePassive = false;
FtpWebResponse response = (FtpWebResponse)ftpRequest.GetResponse();
StreamReader streamReader = new StreamReader(response.GetResponseStream());
List<string> directories = new List<string>();
string line = streamReader.ReadLine();
while (!string.IsNullOrEmpty(line))
{
directories.Add(line);
line = streamReader.ReadLine();
}
streamReader.Close();
return true;
A firewall issue when dropping into a passive-mode port? Can you connect to the FTP server with Filezilla?
Your probably getting a timeout, did you check the firewall? it could be blocking your connection.
Related
I am trying to connect to a remote FTP server that uses Active mode.
I have implemented a simple C# FTP client using .NET Core 3.1
var filename = _ftpServerUrl + "/" + targetFilePath;
System.Net.FtpWebRequest request = (System.Net.FtpWebRequest)System.Net.WebRequest.Create(filename);
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Proxy = null;
request.Credentials = new NetworkCredential(username, password);
request.KeepAlive = false;
request.UsePassive = false;
request.UseBinary = true;
byte[] fileContents;
using (StreamReader sourceStream = new StreamReader(fileStream))
{
fileContents = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd());
}
request.ContentLength = fileContents.Length;
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(fileContents, 0, fileContents.Length);
}
This works excellent when running in VS 2019 on localhost.
But when the code is running as an Azure function (v3) in Azure, I get this response from the server:
500 Syntax error, command unrecognized
I understand the FTP Active mode requires the client to send its public IP address to the server, which will then try and open and incoming connection to the client.
Is there anything in the Azure Function sandbox preventing this?
I have even tried running my Azure Function using an App Service plan with a static public IP, without any luck.
Is there anyone out there who have had success connecting to an FTP server using Active Mode from an Azure App Service or Function?
FTP servers do not "use active mode". It's the FTP clients that may choose to use the active mode. But nowadays with ubiquitous firewalls and NATs, using the active mode can hardly work. That's true even more so in case of cloud services, VMs, and even more so with such a specific virtual services as Azure functions.
The FTP active mode needs an incoming connection. That's prevented by the Azure firewall and NATs. I'd expect that the VMs running the Azure functions won't have any incoming ports forwarded/opened. Why would they? It goes against the purpose of the Azure functions. They are intended to run a short-lived functionality, not servers. The active FTP mode is a strange beast in this respect. There's hardly any other client-side functionality that needs incoming ports.
Allowing the incoming connections (if possible at all in Azure functions) is not a programming question. No change in your code would help. In general, you should use the passive mode.
For some background, see my article about a network configuration needed for the active and passive FTP modes.
here is my code :
FtpWebRequest reqFTP = null;
Stream ftpStream = null;
string currentDir = string.Format("ftp://{0}", "10.10.10.46/E:/SERVER");
//string currentDir=string.Format("ftp://{0}","10.10.10.21/var/www/webdav/SERVER");
reqFTP = (FtpWebRequest)FtpWebRequest.Create(currentDir);
reqFTP.Method = WebRequestMethods.Ftp.MakeDirectory;
reqFTP.UseBinary = true;
reqFTP.Credentials = new NetworkCredential("core", "c0relynx");
FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
ftpStream = response.GetResponseStream();
ftpStream.Close();
response.Close();
Whenever I execute this code I get the exception "System error".
If I use the url "10.10.10.21/var/www/webdav/SERVER" I get the exception "The remote server returned an error: (530) Not logged in".
10.10.10.46 is a windows PC and 10.10.10.21 has Ubuntu.
Can anyone tell me where I have gone wrong and what I must do to resolve this?
Your code itself is not the problem. It's not how I generally do things, but it does work for me on my test rig. The problem is most likely related to the server configuration and/or credentials.
The (530) Not logged in error is almost always because your credentials are wrong. Check that the username and password are correct for the Ubuntu server by using a standard FTP client like Filezilla or even the Windows command-line ftp client.
As for the other message, it is most likely a generic 500 response returned by the other server. There are too many possible reasons for this and not enough information.
The only thing I can suggest is again to try the operation with the same credentials in some other FTP client to see what is actually happening. Unless you're keen to use a packet trace, and know enough about the FTP protocol to understand what the packets are telling you.
At this point you're going to have to do some diagnostics on the FTP server, which is outside the scope of Stack Overflow. The superuser site is better suited for this.
(Related to: FTP directory listing returned as HTML instead of simple Linux ls output)
How can I force a C# program (FtpWebRequest) to use a direct IP to get onto the Internet instead of going through an HTTP proxy? (My knowledge of IT networks and related terminology is scant. Apologies in advance.)
To break out from the internal company network there is
Indirect way via the IP of a (HTTP) proxy server.
Direct IP of an internet service (not a proxy server).
I know this because, when using FileZilla with / without the proxy set in Internet Explorer, then on the remote FTP server, the logs either show the IP of the proxy, or the direct IP.
Code using C# FtpWebRequest to connect to FTP server outside of the company.
FtpWebRequest request = WebRequest.Create(uri) as FtpWebRequest;
request.Method = WebRequestMethods.Ftp.ListDirectory;
request.Credentials = server.Credential;
request.KeepAlive = true;
request.UsePassive = true;
request.EnableSsl = false;
//proxy options
//1.
// do nothing
//2.
request.Proxy = null;
//3. setup HTTP proxy
request.Proxy = new WebProxy(proxyuri, true);
request.Proxy.Credentials = System.Net.CredentialCache.DefaultCredentials;
request.Proxy.Credentials = new NetworkCredential("Username", "Password");
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
while (!reader.EndOfStream)
{ ... }
When I set the proxy, then the C# program (obviously) uses the proxy server to get to the FTP server. However because this is an HTTP proxy, the directory listing is returned as HTML and deleting, uploading, and making directories is not possible. The program needs to delete files, create folders on the FTP.
Similarly, when not setting the proxy, then the program uses the settings in Internet Explorer, where the proxy is set, which then again uses the HTTP proxy.
In the code, setting the proxy to null (request.Proxy = null OR WebRequest.DefaultWebProxy OR GlobalProxySelection.GetEmptyWebProxy() OR new WebProxy(); ) causes an exception "The remote server returned an error: (550) File unavailable (e.g., file not found, no access)."
This problem only occurs for one particular external FTP server (that happens to be running vsftpd). I tested using a different external FTP and both the proxy and the non proxy / direct connection work.
Questions
1. It seems the C# program can only breakout using the proxy. Why, when the proxy is not set, the program does not use the direct IP?
2. How can I force the program to use the direct IP?
3. Could the problem be due to the FTP server (vsftpd)?
The windows hosts file (%systemroot%\system32\drivers\etc) had erroneous entries. I am not exactly sure which entry was the problem but the file now only contains one line
127.0.0.1 localhost
I try to establish a FTP connection using the FtpWebRequest. I need to establish the connection through a squid proxy server, that requires me to send a CONNECT command first.
I have tried the code below, but this results in a GET request to the proxy server, which it refuses.
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://" +server);
request.Credentials = new NetworkCredential(user, pwd);
var webproxy = new WebProxy(new Uri("http://" + proxy+ ":" + proxyPort));
webproxy.UseDefaultCredentials = true;
request.Proxy = webproxy;
request.UsePassive = true;
request.Method = WebRequestMethods.Ftp.ListDirectory;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Is there any way that I can use the FtpWebRequest to establish my connection through the proxy?
If not, do you know a good and hopefully free .NET FTP client that I can use?
Thank you very much for your help.
FtpWebRequest is a "session-less" client, so it doesn't allow you to interact with the remote end while connected. I examined the code of FtpWebRequest.cs and I don't see how you can get it to send a "CONNECT" command.
"CONNECT" command doesn't seem to be part of the standard FTP command set, so I can't wrap my brain how this fits into something that an FTP library should do.
A good free FTP client that is session-oriented that I use is "SSH.NET Library" at http://sshnet.codeplex.com/ but I believe it only supports sftp. FtpWebRequest supports ftps and ftp. Find out if your FTP server supports sftp and you might be able to use SSH.NET . If your only option is ftps, I can report that I spent a long time looking for a free .net ftps client and I came away using FtpWebRequest.
FtpWebRequest supports HTTP proxy (and CONNECT command is mandatory part of that support). Your code is correct.
Though the HTTP proxy is not supported uploads (it is for all other operations). So maybe your actual problem is the upload, while you do not mention it.
For FTP uploads through HTTP proxy you have to use a 3rd party FTP client.
For example with WinSCP .NET assembly, you can use:
// Setup session options
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Ftp,
HostName = "example.com",
UserName = "user",
Password = "mypassword",
};
// Configure proxy
sessionOptions.AddRawSettings("ProxyMethod", "3"); // HTTP proxy
sessionOptions.AddRawSettings("ProxyHost", "proxy");
using (Session session = new Session())
{
// Connect
session.Open(sessionOptions);
// Upload file
string localFilePath = #"C:\path\file.txt";
string pathUpload = "/file.txt";
session.PutFiles(localFilePath, pathUpload).Check();
}
For the options for the SessionOptions.AddRawSettings, see raw settings.
Easier is to have WinSCP GUI generate C# FTP code template for you.
Note that WinSCP .NET assembly is not a native .NET library. It's rather a thin .NET wrapper over a console application.
(I'm the author of WinSCP)
I am using C# to upload some file to a ftp server. If the file already existed the FtpWebRequest timed out, so I thought to deleate it first.
However the WebRequestMethods.Ftp.DeleteFile also always times out. Am I doing something wrong?
Here is my code:
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(address);
request.Credentials = new NetworkCredential(Username, Password);
request.KeepAlive = false;
request.Method = WebRequestMethods.Ftp.DeleteFile;
try
{
FtpWebResponse resp = (FtpWebResponse)request.GetResponse();
}
catch (Exception e)
{
...
}
EDIT: Oh and it doesn't matter witch file I am trying to delete. As long as the file exists the request will always time out. If the file doesn't exist a different exception is thrown.
Nothing is wrong with credentials, I can do other operations (upload/download without a problem). Also it's not a server problem, if I connect to it with a client (FileZilla) with the same username / pass everything works as it should.
Thank you for your help.
The thing I have found using this Ftp via FtpWebRequest, is it is inherently a lot slower (since it is using the HTTP protocol over port 80), and it drives me crazy because FileZilla can do it a lot quicker (obviously using FTP protocol over port 20/21). There is a open source ftp component found here, I do not know if it will work for you, but worth a shot.
I know this is a subjective answer that will get downvoted, but personally, using ftp over port 80 is bound to be a lot slower especially on file operations like what you are trying to achieve.
Do you have access to the logs of the FTP server? If you do have a look at what commands the FTPWebRequest is making. It could be that it is trying to list the directory before deleting it.
Another issue maybe that the server is in passive mode, I believe FileZilla may automagicly detect this, check the connection in filezilla to see.
Knowing what commands are sent between client and FTP server could help find out what is causing the timeout. Would it be possible to use a packet analyzer such as Ethereal to capture the communication log?
Alternative approach could be using a third party FTP component and enabling logging in it. Following code uses our Rebex FTP:
// create client
Ftp client = new Ftp();
// enable logging
client.LogWriter = new Rebex.FileLogWriter(#"c:\temp\log.txt", Rebex.LogLevel.Debug);
// connect
client.Connect("ftp.example.org");
client.Login("username", "password");
// browse directories, transfer files
client.DeleteFile("file.txt");
// disconnect
client.Disconnect();