How to send arbitrary FTP commands in C# - c#

I have implemented the ability to upload, download, delete, etc. using the FtpWebRequest class in C#. That is fairly straight forward.
What I need to do now is support sending arbitrary FTP commands such as
quote SITE LRECL=132 RECFM=FB
or
quote SYST
Here's an example configuration straight from our app.config:
<!-- The following commands will be executed before any uploads occur -->
<extraCommands>
<command>quote SITE LRECL=132 RECFM=FB</command>
</extraCommands>
I'm still researching how to do this using FtpWebRequest. I'll probably try WebClient class next. Anyone can point me in the right direction quicker? Thanks!
UPDATE:
I've come to that same conclusion, as of .NET Framework 3.5 FtpWebRequest doesn't support anything except what's in WebRequestMethods.Ftp.*. I'll try a third party app recommended by some of the other posts. Thanks for the help!

I don't think it can be done with FtpWebRequest... The only way to specify a FTP command is through the Method property, and the documentation states :
Note that the strings defined in the WebRequestMethods.Ftp class are the only supported options for the Method property. Setting the Method property to any other value will result in an ArgumentException exception.
SITE and SYST are not among the predefined options, so I guess you're stuck...
Don't waste time to try the WebClient class, it will give you even less flexibility than FtpWebRequest.
However, there are plenty of third-party FTP implementation, open source or commercial, and I'm pretty sure some of them can handle custom commands...

The FtpWebRequest won't help you as Thomas Levesque has said in his answer. You can use some third party solutions or the following, simplified TcpClient based code which I have refactored from an answer written in Visual Basic:
public static void SendFtpCommand()
{
var serverName = "[FTP_SERVER_NAME]";
var port = 21;
var userName = "[FTP_USER_NAME]";
var password = "[FTP_PASSWORD]"
var command = "SITE CHMOD 755 [FTP_FILE_PATH]";
var tcpClient = new TcpClient();
try
{
tcpClient.Connect(serverName, port);
Flush(tcpClient);
var response = TransmitCommand(tcpClient, "user " + userName);
if (response.IndexOf("331", StringComparison.OrdinalIgnoreCase) < 0)
throw new Exception(string.Format("Error \"{0}\" while sending user name \"{1}\".", response, userName));
response = TransmitCommand(tcpClient, "pass " + password);
if (response.IndexOf("230", StringComparison.OrdinalIgnoreCase) < 0)
throw new Exception(string.Format("Error \"{0}\" while sending password.", response));
response = TransmitCommand(tcpClient, command);
if (response.IndexOf("200", StringComparison.OrdinalIgnoreCase) < 0)
throw new Exception(string.Format("Error \"{0}\" while sending command \"{1}\".", response, command));
}
finally
{
if (tcpClient.Connected)
tcpClient.Close();
}
}
private static string TransmitCommand(TcpClient tcpClient, string cmd)
{
var networkStream = tcpClient.GetStream();
if (!networkStream.CanWrite || !networkStream.CanRead)
return string.Empty;
var sendBytes = Encoding.ASCII.GetBytes(cmd + "\r\n");
networkStream.Write(sendBytes, 0, sendBytes.Length);
var streamReader = new StreamReader(networkStream);
return streamReader.ReadLine();
}
private static string Flush(TcpClient tcpClient)
{
try
{
var networkStream = tcpClient.GetStream();
if (!networkStream.CanWrite || !networkStream.CanRead)
return string.Empty;
var receiveBytes = new byte[tcpClient.ReceiveBufferSize];
networkStream.ReadTimeout = 10000;
networkStream.Read(receiveBytes, 0, tcpClient.ReceiveBufferSize);
return Encoding.ASCII.GetString(receiveBytes);
}
catch
{
// Ignore all irrelevant exceptions
}
return string.Empty;
}
You can expect the following flow while getting through the FTP:
220 (vsFTPd 2.2.2)
user [FTP_USER_NAME]
331 Please specify the password.
pass [FTP_PASSWORD]
230 Login successful.
SITE CHMOD 755 [FTP_FILE_PATH]
200 SITE CHMOD command ok.

You can try our Rebex FTP component:
// create client and connect
Ftp client = new Ftp();
client.Connect("ftp.example.org");
client.Login("username", "password");
// send SITE command
// note that QUOTE and SITE are ommited. QUOTE is command line ftp syntax only.
client.Site("LRECL=132 RECFM=FB");
// send SYST command
client.SendCommand("SYST");
FtpResponse response = client.ReadResponse();
if (response.Group != 2)
; // handle error
// disconnect
client.Disconnect();

Use sendCommand("SITE LRECL=242 BLKSIZE=0 RECFM=FB");

Related

Check Load Balancing server using C#

I have four application server for my application.Application is working on all server using load balancing.If one of my server goes down I have to check it manually using my system hosts file.To avoid this manual process I have created one program using C#.I write server IP address one by one in host file and remove previous one.
private void RunWithUAC()
{
List<string> lstIPAddress = new List<string>();
lstIPAddress.Add("1.1.1.1 example.com");
lstIPAddress.Add("1.1.1.1 example.com");
lstIPAddress.Add("1.1.1.1 example.com");
lstIPAddress.Add("1.1.1.1 example.com");
var systemPath = Environment.GetFolderPath(Environment.SpecialFolder.System);
Console.WriteLine(systemPath);
var path = #"C:\Windows\System32\drivers\etc\hosts";
foreach (var item in lstIPAddress)
{
System.IO.File.WriteAllText(path, string.Empty);
try
{
File.WriteAllText(path, item);
WebRequest request = WebRequest.Create("https://example.com");
request.Timeout = 10000;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
}
catch (Exception)
{
MessageBox.Show(item);
}
Thread.Sleep(1000);
}
}
But When second server goes down.It will give me timeout error for third server.
Please check the code and let me know what is wrong with this code.
Probably some kind of connection pooling, HTTP pipelining or keep-alive. This is the wrong approach in the first place.
Connect directly to the right IP (WebRequest.Create("https://1.1.1.1")). If you need to send a Host header add that manually to the request.

Connecting to IRC via a proxy (.NET)

I wish to hide my IP when connecting to IRC via my .NET app. I currently use the IrcDotNet library but it doesn't seems to support proxies.
I've not had much experience with sockets, so I think modifying IrcDotNet would be easier than making my own IRC library. I looked around for socket libraries that handle proxy connections that I could implement in IrcDotNet. I found one called ProxySocket but it only supports BeginConnect not the new ASyncConnect method that IrcDotNet uses.
To break it down, in order of preference, here's what I'm looking for;
An IRC library that supports connecting via a HTTP/SOCKS proxy
A socket library that supports connecting via a HTTP/SOCKS proxy via
ASyncConnect
Example code on how to extend the socket class to support connecting
via a HTTP/SOCKS proxy via ASyncConnect
The version of IrcDotNet I am using is 0.4.1 found at https://launchpad.net/ircdotnet.
Update 1: Still no luck i'm afraid. Fredrik92's answer, while helpful, is not applicable to the version of IrcDotNet I am using (see above).
The IRC.NET library uses the standard Socket class in the System.Net.Sockets namespace.
So you could just modify the IrcDotNet/IrcClient.cs file in the IRC.NET source code (# http://ircdotnet.codeplex.com/SourceControl/latest).
You should add a constructor for proxy enabled IRC clients and call the default constructor.
Then all you should need to do is to modify the Connect methods in the same file (almost at the bottom). Each time they call this.client.BeginConnect(..) you have to add code for connecting to the Proxy (instead of the remote host)
Now you only have to create a new Connect-callback method that sends a HTTP CONNECT request to the proxy. Read the response from the HTTP Proxy and then everything else should work.
In this case I would write the HTTP request as raw ASCII bytes to the Proxy (instead of using the HttpWebRequest class), so that you have full control over the network stream you get in return...
You should add sth. like this to the IrcClient class:
private bool useProxy = false;
private IWebProxy proxy;
private IEnumerable<Uri> proxyRemoteUris;
public IrcClient(IWebProxy proxy)
: this()
{
this.useProxy = true;
this.proxy = proxy;
}
private void ProxyPerformHttpConnect(Uri remoteIrcUri)
{
string httpConnectRequest = string.Format("CONNECT {0}:{1} HTTP/1.1\r\nHost: {2}\r\n\r\n",
remoteIrcUri.Host, remoteIrcUri.Port, this.proxy.GetProxy(remoteIrcUri));
byte[] httpConnectData = Encoding.ASCII.GetBytes(httpConnectRequest);
this.stream.Write(httpConnectData, 0, httpConnectData.Length);
bool responseReady = false;
string responseText = string.Empty;
// Byte-by-byte reading required, because StringReader will read more than just the HTTP response header
do
{
int readByte = this.stream.ReadByte();
if (readByte < 0)
throw new WebException(message: null, status: WebExceptionStatus.ConnectionClosed);
char readChar = (char)(readByte); // Only works because HTTP Headers are ASCII encoded.
responseText += readChar;
responseReady = responseText.EndsWith("\r\n\r\n");
} while (!responseReady);
int statusStart = responseText.IndexOf(' ') + 1;
int reasonStart = responseText.IndexOf(' ', statusStart) + 1;
int reasonEnd = responseText.IndexOfAny(new char[] { '\r', '\n'});
HttpStatusCode responseStatus = (HttpStatusCode)(int.Parse(responseText.Substring(responseText.IndexOf(' ') + 1, length: 3)));
if (responseStatus != HttpStatusCode.OK)
{
string reasonText = responseText.Substring(reasonStart, reasonEnd - reasonStart);
if (string.IsNullOrWhiteSpace(reasonText))
reasonText = null;
throw new WebException(reasonText, WebExceptionStatus.ConnectFailure);
}
// Finished Response Header read...
}
private void ProxyConnectCallback(IAsyncResult ar)
{
try
{
this.client.EndConnect(ar);
this.stream = this.client.GetStream();
bool proxyTunnelEstablished = false;
WebException lastWebException = null;
foreach (Uri remoteIrcUri in this.proxyRemoteUris)
{
if (this.client.Connected == false)
{
// Re-establish connection with proxy...
Uri proxyUri = this.proxy.GetProxy(remoteIrcUri);
this.client.Connect(proxyUri.Host, proxyUri.Port);
}
try
{
ProxyPerformHttpConnect(remoteIrcUri);
proxyTunnelEstablished = true;
break;
}
catch (WebException webExcept)
{
lastWebException = webExcept;
}
}
if (!proxyTunnelEstablished)
{
OnConnectFailed(new IrcErrorEventArgs(lastWebException));
return;
}
this.writer = new StreamWriter(this.stream, Encoding.Default);
this.reader = new StreamReader(this.stream, Encoding.Default);
HandleClientConnected((IrcRegistrationInfo)ar.AsyncState);
this.readThread.Start();
this.writeThread.Start();
OnConnected(new EventArgs());
}
catch (Exception ex)
{
OnConnectFailed(new IrcErrorEventArgs(ex));
}
}
The code for the proxy handling in all Connect methods of the IrcClient class would thus look sth. like this:
// Code snippet to insert before the call to this.client.BeginConnect(...)
if (this.useProxy)
{
// Assign host and port variables for EndPoint objects:
// var host = remoteEP.Address;
// var port = remoteEP.Port;
this.proxyRemoteUris = new Uri[] { new Uri(string.Format("irc://{0}:{1}/", host, port)) };
// Replace the line above with the following line in the method where an array of IP addresses is specified as a parameter
// this.proxyRemoteUris = from ip in addresses select new Uri(string.Format("irc://{0}:{1}/", ip, port));
Uri proxyUri = this.proxy.GetProxy(this.proxyRemoteUris.First());
string proxyHost = proxyUri.Host;
int proxyPort = proxyUri.Port;
this.client.BeginConnect(proxyHost, proxyPort, ProxyConnectCallback, registrationInfo);
}
else
// Original this.client.BeginConnect(...) call here...

Email client app exceptions

I am developing an app with xamarin studio. My goal is to connect to pop3 and download emails to my app.
I am using the following code but I am facing these issues:
a) an exception on sslstream.AuthenticateAsClient("pop.gmail.com");. (The authentication or decryption has failed).
b)everywhere I have sw.Flush() I am taking exception: This operation is invalid until it is successfully authenticated.
TcpClient tcpclient = new TcpClient();
tcpclient.Connect("pop.gmail.com", 995);
System.Net.Security.SslStream sslstream = new SslStream(tcpclient.GetStream());
sslstream.AuthenticateAsClient("pop.gmail.com");
StreamWriter sw = new StreamWriter(sslstream);
System.IO.StreamReader reader = new StreamReader(sslstream);
sw.WriteLine("USER myusername");
sw.Flush();
sw.WriteLine("PASS *****");
sw.Flush();
sw.WriteLine("RETR 1");
sw.Flush();
sw.WriteLine("Quit ");
sw.Flush();
string str = string.Empty;
string strTemp = string.Empty;
while((strTemp = reader.ReadLine()) !=null){
if(".".Equals(strTemp)){
break;
}
if(strTemp.IndexOf("-ERR") != -1){
break;
}
str +=strTemp;
}
reader.Close();
sw.Close();
tcpclient.Close();
EDIT
I used mailkit and it is a great solution. I can retrieve emails but i have a problem. When i have download a number of mails(not specific number. For deferent account was deferent number of mails)
I am taking the following error:
system.ArgumentOutOfRangeException on: var message = client.GetMessage(i, cancel.Token);
My code for the login:
partial void btnlogin (NSObject sender)
{
using (var client = new Pop3Client ()) {
var credentials = new NetworkCredential (Convert.ToString(txtusername.Text).Trim(), Convert.ToString(txtpassword.Text).Trim());
// Note: if the server requires SSL-on-connect, use the "pops" protocol instead
var uri = new Uri (Convert.ToString("pops://pop.gmail.com"));
using (var cancel = new CancellationTokenSource ()) {
client.Connect (uri, cancel.Token);
client.Authenticate (credentials, cancel.Token);
int count = client.GetMessageCount (cancel.Token);
var list= new List<string>();
for (int i = 0; i < count; i++) {
var message = client.GetMessage (i, cancel.Token);
Console.WriteLine ("From: {0}", message.From);
list.Add(Convert.ToString(message.From));
}
client.Disconnect (true, cancel.Token);
}
}
}
I came here to suggest using MailKit instead of writing your own library for this. MailKit is also specifically meant to work with Xamarin (since I work at Xamarin). MailSystem.NET is pretty badly broken (I've ranted about it elsewhere on StackOverflow), so I would definitely not recommend using that.
That said, you may need to look at using this version of the SslStream .ctor as opposed to the one you are using. The problem may be that the default .ctor isn't validating the SSL certificate because it isn't "trusted".
I would use an existing C# library to do this.
At one point in the past, I used MailSystem.NET and was able to port their library to MonoTouch. I am not sure of its license works for you, but you will have a much better time using it than rolling your own.
I also think that writing your own library for this would be a waste of anyone's time. I haven't tried Mail Kit yet (will definitely have to), but I have recently used Rebex Mail when I needed to backup my emails from my email server via POP3. Fortunatelly, it was a one time task only, so I did not have to pay as I only used their 30-day free trial that did not have any limitation.
using Rebex.Mail;
using Rebex.Net;
Pop3 client = new Pop3();
client.Connect("pop.gmail.com", SslMode.Implicit);
client.Login("gmailuser", "password");
var messageInfos = client.GetMessageList(Pop3ListFields.FullHeaders);
foreach (Pop3MessageInfo message in messageInfos)
client.GetMessage(message.SequenceNumber, string.Format(#"C:\gmail-pop3-backup\{0}-{1}.eml", message.Subject, message.UniqueId));
client.Disconnect();

WebSockets in firefox

For implementing my websocket server in C# I'm using Alchemy framework. I'm stuck with this issue. In the method OnReceive when I try to deserialize json object, I get a FormatException:
"Incorrect format of the input string." (maybe it's different in english, but I'm getting a localized exception message and that's my translation :P). What is odd about this is that when I print out the context.DataFrame I get: 111872281.1341000479.1335108793.1335108793.1335108793.1; __ad which is a substring of the cookies sent by the browser: __gutp=entrystamp%3D1288455757%7Csid%3D65a51a83cbf86945d0fd994e15eb94f9%7Cstamp%3D1288456520%7Contime%3D155; __utma=111872281.1341000479.1335108793.1335108793.1335108793.1; __adtaily_ui=cupIiq90q9.
JS code:
// I'm really not doing anything more than this
var ws = new WebSocket("ws://localhost:8080");
C# code:
static void Main(string[] args) {
int port = 8080;
WebSocketServer wsServer = new WebSocketServer(port, IPAddress.Any) {
OnReceive = OnReceive,
OnSend = OnSend,
OnConnect = OnConnect,
OnConnected = OnConnected,
OnDisconnect = OnDisconnect,
TimeOut = new TimeSpan(0, 5, 0)
};
wsServer.Start();
Console.WriteLine("Server started listening on port: " + port + "...");
string command = string.Empty;
while (command != "exit") {
command = Console.ReadLine();
}
Console.WriteLine("Server stopped listening on port: " + port + "...");
wsServer.Stop();
Console.WriteLine("Server exits...");
}
public static void OnReceive(UserContext context) {
string json = "";
dynamic obj;
try {
json = context.DataFrame.ToString();
Console.WriteLine(json);
obj = JsonConvert.DeserializeObject(json);
} catch (Exception e) {
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
return;
}
}
On the C# side I'm using Newtonsoft.Json, though it's not a problem with this library...
EDIT:
One more thing - I browsed through the code in here: https://github.com/Olivine-Labs/Alchemy-Websockets-Example and found nothing - I mean, I'm doing everything the same way authors did in this tutorial...
EDIT:
I was testing the above code in Firefox v 17.0.1, and it didn't work, so I tested it under google chrome, and it works. So let me rephrase the question - what changes can be made in js, so that firefox would not send aforementioned string?
I ran into the same issue - simply replacing
var ws = new WebSocket("ws://localhost:8080");
with
var ws = new WebSocket("ws://127.0.0.1:8080");
fixed the issue for me.
In C# console app I connect the client to the server using :
var aClient = new WebSocketClient(#"ws://127.0.0.1:81/beef");
Your code above is connecting using
var ws = new WebSocket("ws://localhost:8080");
There could be one of two issues -
First is to see if WebSocketClient works instead.
To make sure your url is of the format ws://ur:port/context. This threw me off for a while.

Top level domain ignorance at using RIPE

I'm developing a simple app in c#, that can check if a domain name is available to puchase for a specific tld.
The method: I downloaded a whois-server list, I send the domain name to its whois server with a TCP client on the protocol 43, and check the servers answer.
The problem: more countries has the same whois server: "whois.ripe.net" .
If I send the full domain name(with tld), the server's answer is always "No entries found in source RIPE.". If I send the domain name without tld, I dont get any tld specific data about the status of the domain name.
The method I use:
private string GetWhoisInformation(string whoisServer, string url)
{
try
{
StringBuilder stringBuilderResult = new StringBuilder();
TcpClient tcpClinetWhois = new TcpClient(whoisServer, 43);
NetworkStream networkStreamWhois = tcpClinetWhois.GetStream();
BufferedStream bufferedStreamWhois = new BufferedStream(networkStreamWhois);
StreamWriter streamWriter = new StreamWriter(bufferedStreamWhois);
streamWriter.WriteLine(url);
streamWriter.Flush();
StreamReader streamReaderReceive = new StreamReader(bufferedStreamWhois);
while (!streamReaderReceive.EndOfStream)
stringBuilderResult.AppendLine(streamReaderReceive.ReadLine());
return stringBuilderResult.ToString();
}
catch
{
return "lekérdezés sikertelen";
}
}
Example:
I do:
GetWhoisInformation("whois.ripe.net", "pokerstars.hu")
The server's answer:
%ERROR:101: no entries found
%
% No entries found in source RIPE.
for the next command:
GetWhoisInformation("whois.ripe.net", "pokerstars")
the result contains several blocks like this:
% Information related to '80.65.254.128 - 80.65.254.159'
inetnum: 80.65.254.128 - 80.65.254.159
netname: Pokerstars
descr: Hosting
country: GB
admin-c: DC77-RIPE
tech-c: JM2352-RIPE
status: assigned PA
mnt-by: manx-telecom-mnt
changed: bill.hogg#manx-telecom.com 20101123
source: RIPE
There's no information about the domain name "pokerstars.hu". Of course, I get exactly the same answers if I want to check pokerstars.va. Pokerstars.hu is a registred domain, pokerstars.va is not.
How can I find the correct status of a domain name?
RIPE does not serve as a ccTLD whois server for any domains; like ARIN, it contains only netblock information. Each ccTLD has its own root whois server (or, that is, some of them don't have a proper whois service -- for example, the Spanish .es registry requires that you use a web client, with an obnoxious CAPTCHA you have to fill in every time).
See also http://www.ripe.net/data-tools/db although it is not very explicit about what the database does not contain.
You can get the address of the authoritative whois server by requesting the ccTLD's information from whois.iana.org.
vnix$ whois -h whois.iana.org hu | fgrep whois:
whois: whois.nic.hu
See also http://www.iana.org/domains/root/db/
I tried your code against whois.melbourneit.net and it found one of my domains no trouble. I was able to reproduce your problem running against RIPE and so I tried the same query interactively on their website - and had the same result. There's nothing wrong with your code.
tripleee is right about whois.nic.hu, I successfully used it to resolve pokerstars.hu - which leaves me wondering what the blazes is purpose of the RIPE whois server.
Thanks to triplee for showing us how to obtain the whois server friendly-name for a ccTLD.
You may find this useful:
using System;
using System.IO;
using System.Net.Sockets;
using System.Text;
namespace Whois
{
class Program
{
static void Main(string[] args)
{
string tldWhoisServer = "whois.iana.org";
string ccTldServer, query = null;
Console.Write("Query> ");
while ((query = Console.ReadLine()) != string.Empty)
{
string tld = query.Substring(query.LastIndexOf('.') + 1);
string foo = GetWhoisInformation(tldWhoisServer, tld);
foo = foo.Remove(0, foo.IndexOf("whois:") + 6).TrimStart();
ccTldServer = foo.Substring(0, foo.IndexOf('\r'));
Console.WriteLine(GetWhoisInformation(ccTldServer, query));
Console.Write("Query> ");
}
}
static string GetWhoisInformation(string whoisServer, string url)
{
try
{
StringBuilder stringBuilderResult = new StringBuilder();
TcpClient tcpClinetWhois = new TcpClient(whoisServer, 43);
NetworkStream networkStreamWhois = tcpClinetWhois.GetStream();
BufferedStream bufferedStreamWhois = new BufferedStream(networkStreamWhois);
StreamWriter streamWriter = new StreamWriter(bufferedStreamWhois);
streamWriter.WriteLine(url);
streamWriter.Flush();
StreamReader streamReaderReceive = new StreamReader(bufferedStreamWhois);
while (!streamReaderReceive.EndOfStream)
stringBuilderResult.AppendLine(streamReaderReceive.ReadLine());
return stringBuilderResult.ToString();
}
catch
{
return "Query failed";
}
}
}
}

Categories

Resources