C# Telnet client give none/incomplete output - c#

I have a problem with the basic implementation of telnet client in C#. When I try to connect to the remote computer in local network via command line (telnet 192.168.0.255 23), there are no problems, but with this code, I cannot get for me any logical output
(just chars "??%?? ?? ??'??¬?? ??").
TcpClient telnetClient = new TcpClient("192.168.0.255", 23);
NetworkStream telnetStream = telnetClient.GetStream();
byte[] data = new Byte[4];
string responseData = String.Empty;
int bytes = telnetStream.Read(data, 0, data.Length);
while (true){
responseData += Encoding.ASCII.GetString(data, 0, bytes);
bytes = telnetStream.Read(data, 0, data.Length);
if (!telnetStream.DataAvailable)
break;
}
Console.WriteLine(responseData);
telnetClient.Close();
I realize when I try to get output from different public servers (for example. telehack.com), I get just in some cases first line of output. But output, which is provided via command line is much much extensive.
Telnet connection to remote pc in LAN via telnet and c#
Connection to public pc via telnet and c#
Could you please tell me what I doing terribly wrong? :)
Thank you all for help.

The first bytes send via Telnet in the case of telehack.com are Command bytes (see https://en.wikipedia.org/wiki/Telnet#Telnet_data ). They Start with 0xFF and then the command. You can see them clearly in the example below in the debug window (numbers there are in decimal).
I tried this with your (extended) C# script:

Related

Send data to remote server using Sockets

I want send data to remote server i know its IP address and Port number. Let say it is xxx.xxx.xx.xx and port number is 123. It works with TCP. I want to send first-last name, email, and host name where host name is the new name which i am going to give my machine. Server should give me response in the form of key value as 123-01234. Here I do not understand how i would send data to server using socket. I did work with just simple strings. I have one last more question, Have i need to make server program in it.
public void Connect(String server)
{
Int32 port = 123;
TcpClient client = new TcpClient(server, port);
string FNAME = "reet";
Byte[] data = System.Text.Encoding.ASCII.GetBytes(FNAME);
NetworkStream stream = client.GetStream();
stream.Write(data, 0, data.Length);
Console.WriteLine("Sent: {0}", FNAME);
data = new Byte[256];
String responseData = String.Empty;
Int32 bytes = stream.Read(data, 0, data.Length);
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
Console.WriteLine("Received: {0}", responseData);
stream.Close();
client.Close();
}
To open a socket, you can either use the Socket type, or the TcpClient type (assuming it is TCP). The IP address and port are specified in the constructor for either. Then you need to decide whether you're going to use the Socket API, vs the NetworkStream API, to actually do the communications. If you're using a raw Socket (.Client on a TcpClient), then you use the Send and Receive methods (and the related async options). If you prefer a Stream, then that is .GetStream() on TcpClient, or new NetworkStream(socketInstance) for Socket, and Read / Write. With a Stream, you can of course wrap it in a StreamReader / StreamWriter if you want a simple text API, but it isn't clear whether your socket API is text or binary. You mention wanting to receive 123-01234, but that could be encoded many different ways, so ultimately you need to be very clear about what the socket API expects, at the byte level.

How to implement IPP gateway using C#?

I need to develop a Internet Printing Protocol gateway in .Net that will receive the print jobs fired from IOS using the AirPrint client. The gateway will receive the document fired and release it to the print queue. I am able to broadcast my print services using the SDK provided by Apple. However, when I listen on a port to receive network streams of a document, I am not able to detect the end of stream received as the client keeps on sending streams. My guess is we have to read the attributes and respond accordingly, but I have no idea of these attributes. Below is the code that I am currently using:
IPAddress ipAddress = IPAddress.Parse("10.0.0.13");
IPAddress tcpListener = new TcpListener(ipAddress, 631);
tcpListener.Start();
while (true)
{
TcpClient tcpClient = tcpListener.AcceptTcpClient();
byte[] bytes = new byte[2560];
NetworkStream stream = tcpClient.GetStream();
stream.Read(bytes, 0, bytes.Length);
string mstrMessage = Encoding.ASCII.GetString(bytesReceived, 0, bytesReceived.Length);
string Continue = "HTTP/1.1 100 Continue\r\n\r\nHTTP/1.1 200 OK\r\nCache-Control: no-cache\r\nDate: " + dateTime + "\r\nPragma: no-cache\r\nTransfer-Encoding: chunked\r\nContent-Type: application/ipp\r\n\r\nattributes-charset utf-8 attributes-natural-language en-us compression-supported none printer-is-accepting-jobs true document-format-supported application/pdf\r\n\r\n0\r\n";
bytesSent = Encoding.ASCII.GetBytes(mstrResponse);
stream.Write(bytesSent, 0, bytesSent.Length);
}
You should check the stream.Read for the returning value.
If it isn't zero you have incoming bytes from the TcpClient:
var bytesLength = 0;
do
{
bytesLength = stream.Read(bytes, 0, bytes.Length);
if (bytesLength == 0) return;
}
while(bytesLength > 0);
You need to understand the level of communication. You're not even reading or writing proper IPP messages yet. 100 continue is purley HTTP related.
Even though Apples Spec for AirPrint is not publicly available there's still a lot of information online. In short: AirPrint is based on IPP. As for the supported PDL PDF is a good choice but not the only one. iOS first checks the printers capabilities. It's up to you what kind of (virtual) print-server you offer.
(In case you have a business case and require a remote developer, don't hestitate to contact us.)

HttpWebRequest through two proxies

I have recently set up a website which uses geographic DNS to resolve the DNS to two different IP's depending on your location.
However, this means to monitor the websites, I need to make sure the site is available in both geographical locations. To do this I wrote a small program in .net to continually try and HttpWebRequest to get a small html file on the website once using the local internet settings and once using a proxy based in the region which will resolve the name to the second IP address.
This works fine on my laptop at home, however in the office, to connect to the internet on almost all machines you will need to go via a proxy, which means the proxy I set earlier no longer works.
What I need to be able to do is send the request through the office proxy, then through the proxy in the remote country and finally to the website.
Let me know if this is not clear enough!
First you need to ensure that both proxies are HTTPS and they both support CONNECT method, i.e. "proxy chaining". Design of usual HTTP protocol doesn't provide support for "proxy chaining".
The idea is to establish 2 CONNECT tunnels, one inside another.
The algorithm is the following:
Connect to the 1st proxy via TCP
Request CONNECT tunnel to 2nd proxy
Once tunnel is created, request tunnel to target host
Send request. Request will go to target host through proxy #1 and proxy #2.
Below is a sample code which I have tested on my box:
string host = "encrypted.google.com";
string proxy2 = "213.240.237.149";//host;
int proxyPort2 = 3128;//443;
string proxy = "180.183.236.63";//host;
int proxyPort = 3128;//443;
byte[] buffer = new byte[2048];
int bytes;
// Connect to the 1st proxy
TcpClient client = new TcpClient(proxy, proxyPort);
NetworkStream stream = client.GetStream();
// Establish tunnel to 2nd proxy
byte[] tunnelRequest = Encoding.UTF8.GetBytes(String.Format("CONNECT {0}:{1} HTTP/1.1\r\nHost:{0}\r\n\r\n", proxy2, proxyPort2));
stream.Write(tunnelRequest, 0, tunnelRequest.Length);
stream.Flush();
// Read response to CONNECT request
// There should be loop that reads multiple packets
bytes = stream.Read(buffer, 0, buffer.Length);
Console.Write(Encoding.UTF8.GetString(buffer, 0, bytes));
// Establish tunnel to target host
tunnelRequest = Encoding.UTF8.GetBytes(String.Format("CONNECT {0}:443 HTTP/1.1\r\nHost:{0}\r\n\r\n", host));
stream.Write(tunnelRequest, 0, tunnelRequest.Length);
stream.Flush();
// Read response to CONNECT request
// There should be loop that reads multiple packets
bytes = stream.Read(buffer, 0, buffer.Length);
Console.Write(Encoding.UTF8.GetString(buffer, 0, bytes));
// Wrap into SSL stream
SslStream sslStream2 = new SslStream(stream);
sslStream2.AuthenticateAsClient(host);
// Send request
byte[] request = Encoding.UTF8.GetBytes(String.Format("GET https://{0}/ HTTP/1.1\r\nHost: {0}\r\n\r\n", host));
sslStream2.Write(request, 0, request.Length);
sslStream2.Flush();
// Read response
do
{
bytes = sslStream2.Read(buffer, 0, buffer.Length);
Console.Write(Encoding.UTF8.GetString(buffer, 0, bytes));
} while (bytes != 0);
client.Close();
Console.ReadKey();

Converting TN5250 Encoding in C#

I have a connection to IBM i (an AS/400) that communicates over a protocol/encoding called TN5250. I haven't been able to match it against any of the encodings listed here; how can I convert this text to something I can use? UTF8, ASCII; anything in a Windows-friendly text format will do. It must not involve buying a third-party library.
Here's some "working" code I found elsewhere. "address" is an IP address.
Socket SocketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
System.Net.IPEndPoint remoteEndPoint = new System.Net.IPEndPoint(IPAddress.Parse("address"), 23);
SocketClient.Connect(remoteEndPoint);
byte[] buffer = new byte[10];
textBox1.Text += Receive(SocketClient, buffer, 0, buffer.Length, 10000).Trim() + "\r\n";
}
public static string Receive(Socket socket, byte[] buffer, int offset, int size, int timeout)
{
int startTickCount = Environment.TickCount;
int received = 0; // how many bytes is already received
do
{
if (Environment.TickCount > startTickCount + timeout)
throw new Exception("Timeout.");
try
{
received += socket.Receive(buffer, offset + received, size - received, SocketFlags.None);
return Encoding.GetEncoding(37).GetString(buffer, 0, buffer.Length);
//byte[] buf = Encoding.Convert(Encoding.GetEncoding("iso-8859-1"), Encoding.UTF8, buffer);
//return Encoding.GetEncoding("IBM500").GetString(buf, 0, buffer.Length);
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.WouldBlock ||
ex.SocketErrorCode == SocketError.IOPending ||
ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
{
// socket buffer is probably empty, wait and try again
Thread.Sleep(30);
}
else
throw ex; // any serious error occurr
}
} while (received < size);
return "";
}
This is a Telnet connection. Works fine in a Windows telnet window. The solution I really want is a way to capture the stdout from the telnet session, but apparently terminal programs like Telnet don't write to stdout.
The TN5250J project is a working TN5250 client written in Java.
TN5250 is the IBM protocol that rides on top of Telnet. It is intended for the IBM midrange family of 'dumb' green screen terminals. This family is block mode, meaning the host sends a full display panel out to the client in one transmission, and the client sends a full display panel back to the host in one single transmission. This, as opposed to a character-by-character transmission.
As a very high level overview, the 5250 protocol describes how to format the display (start/stop field, field attributes like underline and colour) as well as what function keys are acceptable. The client needs to understand these formatting instructions in order to properly render the data coming from the host. Likewise, the client does not send back the full display panel including constants and formatting; instead, it sends back the input-capable fields.
There is no stdout per se; the human readable display panel requires rendering by the client. You may get a good sense for the raw data by using Wireshark to capture the packets and comparing them to an actual TN5250 display showing the same transaction.
From this article, it looks the encoding scheme is EBCDIC character-encoding scheme.
See How to convert between ASCII and EBCDIC character codes for conversion details. It's in VB, but you should be able to convert it to C#. There is also an implementation on John Skeet's page here
How to convert from EBCDIC to ASCII in C#. From this post, looks like you might be able to use the 37 IBM037 IBM EBCDIC (US-Canada) encoding from the list you provided: Encoding ebcdic = Encoding.GetEncoding("IBM037");
TN 5250 is not an encoding. It is a highly complex protocol.
The specification can be found here:
http://www.ietf.org/rfc/rfc1205.txt
(Note that this spec is not even complete)
There is no easy conversion. You have to write thousands of lines of code or use an already existing project like for example this one in C++ for Linux and Windows:
http://sourceforge.net/projects/tn5250/files/
I did not find anything in C#

Sending a image file using a socket in C# (Large Data)

i want to send a large data (image) approx . 1MB file though a socket connection
Question 1
following code snippet of the socket client which i currently use to send a a text message .. how i can modify this to send a file ?
NetworkStream serverStream = clientSocket.GetStream();
byte[] outStream = System.Text.Encoding.ASCII.GetBytes(richTextBox1.Text+"$");
serverStream.Write(outStream, 0, outStream.Length);
serverStream.Flush();
Question 2 : What modifications that required in both socket client and server to send and get large files ?
For large data portions you will probably need some kind of transmitting by portions. In your snippet you get all of the data in the array which couldn't be possible if file is large enough (or at least not suitable if it is not just one file to send).
Sending side will be something like that:
const int bufsize = 8192;
var buffer = new byte[bufsize];
NetworkStream ns = socket.GetStream();
using (var s = File.OpenRead("path"))
{
int actuallyRead;
while ((actuallyRead = s.Read(buffer, 0, bufsize)) > 0)
{
ns.Write(buffer, 0, actuallyRead);
}
}
ns.Flush();
Receiving site is just symmetric.
A socket doesn't care if you send text or binary data. Or how much you send. If there's any trouble then it is at the receiving end, code you didn't post. A classic mistake is to forget that a NetworkStream is a stream and not a sequence of packets. The Read() call at the receiving end can return any number of bytes. It won't be the number of bytes you wrote in the Write() call, depending on how routers in between the two machines broke up the IP packets and how much data is buffered in the receiver. You are probably getting away with calling Read only once because the string is short. That is definitely not going to work when you send a lot of data.
You need a protocol to help the receiver figure out when it received all the data. A simple way to do this is by first sending the length of the data. The receiver can then first read that length, then know how long to keep calling Read() to get the rest of the data.
You can arbitrarily extend this protocol by, say, sending the name of the file. Etcetera. Although that by the time you're done, you'd be close to having re-invented FTP.
If all you want to do is to send an image and you don't need any metadata, you can use code like this:
Server:
var listener = new TcpListener(address, port);
listener.Start();
using (var incoming = listener.AcceptTcpClient())
using (var networkStream = incoming.GetStream())
using (var fileStream = File.OpenWrite(imagePath))
{
networkStream.CopyTo(fileStream);
}
listener.Stop();
Client:
var client = new TcpClient();
client.Connect(address, port);
using (var networkStream = client.GetStream())
using (var fileStream = File.OpenRead(imagePath))
{
fileStream.CopyTo(networkStream);
}
client.Close();
If you want to compress the file, you can use GZipStream.
This code uses CopyTo() method, which is available in .Net 4, but you can write it yourself in earlier versions.

Categories