How can I test SMTP is up and running via C# without sending a message.
I could of course try:
try{
// send email to "nonsense#example.com"
}
catch
{
// log "smtp is down"
}
There must be a more tidy way to do this.
You can try saying EHLO to your server and see if it responds with 250 OK. Of course this test doesn't guarantee you that you will succeed sending the mail later, but it is a good indication.
And here's a sample:
class Program
{
static void Main(string[] args)
{
using (var client = new TcpClient())
{
var server = "smtp.gmail.com";
var port = 465;
client.Connect(server, port);
// As GMail requires SSL we should use SslStream
// If your SMTP server doesn't support SSL you can
// work directly with the underlying stream
using (var stream = client.GetStream())
using (var sslStream = new SslStream(stream))
{
sslStream.AuthenticateAsClient(server);
using (var writer = new StreamWriter(sslStream))
using (var reader = new StreamReader(sslStream))
{
writer.WriteLine("EHLO " + server);
writer.Flush();
Console.WriteLine(reader.ReadLine());
// GMail responds with: 220 mx.google.com ESMTP
}
}
}
}
}
And here's the list of codes to expect.
I use this method and classes to validate the credentials (link to github):
public static bool ValidateCredentials(string login, string password, string server, int port, bool enableSsl) {
SmtpConnectorBase connector;
if (enableSsl) {
connector = new SmtpConnectorWithSsl(server, port);
} else {
connector = new SmtpConnectorWithoutSsl(server, port);
}
if (!connector.CheckResponse(220)) {
return false;
}
connector.SendData($"HELO {Dns.GetHostName()}{SmtpConnectorBase.EOF}");
if (!connector.CheckResponse(250)) {
return false;
}
connector.SendData($"AUTH LOGIN{SmtpConnectorBase.EOF}");
if (!connector.CheckResponse(334)) {
return false;
}
connector.SendData(Convert.ToBase64String(Encoding.UTF8.GetBytes($"{login}")) + SmtpConnectorBase.EOF);
if (!connector.CheckResponse(334)) {
return false;
}
connector.SendData(Convert.ToBase64String(Encoding.UTF8.GetBytes($"{password}")) + SmtpConnectorBase.EOF);
if (!connector.CheckResponse(235)) {
return false;
}
return true;
}
SmtpConnectorBase:
internal abstract class SmtpConnectorBase {
protected string SmtpServerAddress { get; set; }
protected int Port { get; set; }
public const string EOF = "\r\n";
protected SmtpConnectorBase(string smtpServerAddress, int port) {
SmtpServerAddress = smtpServerAddress;
Port = port;
}
public abstract bool CheckResponse(int expectedCode);
public abstract void SendData(string data);
}
SmtpConnectorWithoutSsl:
internal class SmtpConnectorWithoutSsl : SmtpConnectorBase {
private Socket _socket = null;
public SmtpConnectorWithoutSsl(string smtpServerAddress, int port) : base(smtpServerAddress, port) {
IPHostEntry hostEntry = Dns.GetHostEntry(smtpServerAddress);
IPEndPoint endPoint = new IPEndPoint(hostEntry.AddressList[0], port);
_socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
//try to connect and test the rsponse for code 220 = success
_socket.Connect(endPoint);
}
~SmtpConnectorWithoutSsl() {
try {
if (_socket != null) {
_socket.Close();
_socket.Dispose();
_socket = null;
}
} catch (Exception) {
;
}
}
public override bool CheckResponse(int expectedCode) {
while (_socket.Available == 0) {
System.Threading.Thread.Sleep(100);
}
byte[] responseArray = new byte[1024];
_socket.Receive(responseArray, 0, _socket.Available, SocketFlags.None);
string responseData = Encoding.UTF8.GetString(responseArray);
int responseCode = Convert.ToInt32(responseData.Substring(0, 3));
if (responseCode == expectedCode) {
return true;
}
return false;
}
public override void SendData(string data) {
byte[] dataArray = Encoding.UTF8.GetBytes(data);
_socket.Send(dataArray, 0, dataArray.Length, SocketFlags.None);
}
}
SmtpConnectorWithSsl:
internal class SmtpConnectorWithSsl : SmtpConnectorBase {
private SslStream _sslStream = null;
private TcpClient _client = null;
public SmtpConnectorWithSsl(string smtpServerAddress, int port) : base(smtpServerAddress, port) {
TcpClient client = new TcpClient(smtpServerAddress, port);
_sslStream = new SslStream(
client.GetStream(),
false,
new RemoteCertificateValidationCallback(ValidateServerCertificate),
null
);
// The server name must match the name on the server certificate.
try {
_sslStream.AuthenticateAsClient(smtpServerAddress);
} catch (AuthenticationException e) {
_sslStream = null;
Console.WriteLine("Exception: {0}", e.Message);
if (e.InnerException != null) {
Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
}
Console.WriteLine("Authentication failed - closing the connection.");
client.Close();
}
}
~SmtpConnectorWithSsl() {
try {
if (_sslStream != null) {
_sslStream.Close();
_sslStream.Dispose();
_sslStream = null;
}
} catch (Exception) {
;
}
try {
if (_client != null) {
_client.Close();
_client = null;
}
} catch (Exception) {
;
}
}
// The following method is invoked by the RemoteCertificateValidationDelegate.
private static bool ValidateServerCertificate(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors) {
if (sslPolicyErrors == SslPolicyErrors.None)
return true;
Console.WriteLine("Certificate error: {0}", sslPolicyErrors);
// Do not allow this client to communicate with unauthenticated servers.
return false;
}
public override bool CheckResponse(int expectedCode) {
if (_sslStream == null) {
return false;
}
var message = ReadMessageFromStream(_sslStream);
int responseCode = Convert.ToInt32(message.Substring(0, 3));
if (responseCode == expectedCode) {
return true;
}
return false;
}
public override void SendData(string data) {
byte[] messsage = Encoding.UTF8.GetBytes(data);
// Send hello message to the server.
_sslStream.Write(messsage);
_sslStream.Flush();
}
private string ReadMessageFromStream(SslStream stream) {
byte[] buffer = new byte[2048];
StringBuilder messageData = new StringBuilder();
int bytes = -1;
do {
bytes = stream.Read(buffer, 0, buffer.Length);
// Use Decoder class to convert from bytes to UTF8
// in case a character spans two buffers.
Decoder decoder = Encoding.UTF8.GetDecoder();
char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
decoder.GetChars(buffer, 0, bytes, chars, 0);
messageData.Append(chars);
// Check for EOF.
if (messageData.ToString().IndexOf(EOF) != -1) {
break;
}
} while (bytes != 0);
return messageData.ToString();
}
}
You could open up the port (25) with a socket or TcpClient and see if it responds.
Open a socket connection to the smtp server on port 25 and see if you get anything. If not, no smtp server.
Here is a nice open source tool (does more than MX):
http://www.codeproject.com/KB/IP/DNS_NET_Resolver.aspx
Related
I have a problem with my chat app : it doesn't work over the network . I tried port-forwarding and other similar methods. I'm starting to question my code . I'm new to networking so please help me with this. I heard of another method using System.Net.Sockets but I haven't tried that yet . I heard that Sockets are pretty similar to TcpListener so I don't know what to say about this. I made sure I used the correct IP address , the AddressFamily.InterNetwork. Here is my code :
static TcpListener server;
public static void ListenThread()
{
TcpClient client = null;
NetworkStream stream = null;
ClientConnection currentClientConnection = new ClientConnection();
while (true)
{
if(client == null)
{
client = server.AcceptTcpClient();
stream = client.GetStream();
currentClientConnection = new ClientConnection(client, stream);
clients.Add(currentClientConnection);
currentConnections++;
// Logging
string text = "A Client connection establieshed ! Connections : " + currentConnections;
Console.WriteLine(text);
Logger.WriteToLog(text);
}
int bufferSize = client.ReceiveBufferSize;
byte[] buffer = new byte[bufferSize];
int i;
string data = null;
try
{
while ((i = stream.Read(buffer, 0, bufferSize)) != 0)
{
data = Encoding.ASCII.GetString(buffer, 0, i);
data = ProcessData(data);
if (data == "/disconnect")
{
clients.Remove(currentClientConnection);
currentConnections--;
// Logging
string text = "A user left the server ! Connections : " + currentConnections;
Console.WriteLine(text);
Logger.WriteToLog(text);
SendToAllClients(string.Format("[Server]>> A user left the chat!"), client);
client.Close();
stream.Close();
client = null;
break;
}
else
{
SendToAllClients(data, client);
}
}
}
catch { };
}
}
static void InitialiseServer()
{
Console.Write("Enter a port : ");
serverPort = int.Parse(Console.ReadLine());
Console.WriteLine();
IPAddress localMachineIP = GetLocalIPAddress();
try
{
Console.WriteLine("Initialising Server...");
server = new TcpListener(localMachineIP,serverPort);
Console.WriteLine("Server initialised !");
}
catch(Exception e)
{
Console.ForegroundColor = ConsoleColor.Red;
string text = string.Format("An error has occured while initalising server under IP={0} and port={1} . {2}", localMachineIP, serverPort, e.Message);
Console.WriteLine(text);
Logger.WriteToLog(text);
Console.ForegroundColor = baseColor;
}
Console.Title = string.Format("Server initailised under {0}:{1}",localMachineIP.ToString(),serverPort);
}
public static IPAddress GetLocalIPAddress()
{
var host = Dns.GetHostEntry(Dns.GetHostName());
foreach (var ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
return ip;
}
}
return null;
}
I have created a simple C# client application. Once it connects to the server it should read the messages sent from the server. It also has the ability to send messages to server too. However I am unable to figure out to correct way to read the data.
I am spawning a thread once it connects to the server. The thread runs in infinite loop and have two interfaces each for reading and writing. Connect() method is called from a ButtonClick event.
My code snippet is as below:
namespace WpfApp1
{
public class TCPClientClass
{
private StreamWriter SwSender;
NetworkStream Sender;
NetworkStream Receiver;
//private StreamReader SrReciever;
private Thread thrMessaging;
TcpClient tcp;
bool connected = false;
public bool Connected { get { return connected; } set { connected = value; } }
//public bool Connect(IPAddress IP, int nPortNo)
public async Task Connect(IPAddress IP, int nPortNo)
{
tcp = new TcpClient();
try
{
//tcp.Connect(strIPAddress.Parse("192.168.137.1"), 2000);
// tcp.Connect(IP , nPortNo);
await tcp.ConnectAsync(IP, nPortNo);
thrMessaging = new Thread(new ThreadStart(ThreadFunction));
thrMessaging.Start();
Connected = true;
}
catch
{
MessageBox.Show("Unable to connect to server");
//return false;
}
//return true;
}
public void Disconnect()
{
Sender?.Close();
Receiver?.Close();
tcp?.Close();
//tcp?.Client.Disconnect(false);
thrMessaging.Abort();
Connected = false;
}
private void ThreadFunction()
{
while (thrMessaging.IsAlive)
DoTasks();
}
private void DoTasks()
{
if (Connected)
{
var a = ReadMessages();
SendMessages();
}
}
private /*void*/async Task ReadMessages()
{
byte[] data = new byte[4096];
//Int32 bytesRead = 0;
//Task<int> bytesReadTask;
String responseData = String.Empty;
Receiver = tcp.GetStream();
try
{
//bytesReadTask = Receiver.ReadAsync(data, 0, data.Length);
//responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytesReadTask.Result);
var response = await Receiver.ReadAsync(data, 0, data.Length);
MessageBox.Show("Server response was " + response);
Thread.Sleep(1000);
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
private void SendMessages()
{
try
{
string strSendData = "Hello from GUI";
Byte[] data = System.Text.Encoding.ASCII.GetBytes(strSendData);
Sender = tcp.GetStream();
Sender.Write(data, 0, data.Length);
Sender.Flush();
Thread.Sleep(1000);
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
}
}
you should change
var response = await Receiver.ReadAsync(data, 0, data.Length);
MessageBox.Show("Server response was " + response);
to
var response = await Receiver.ReadAsync(data, 0, data.Length);
string result = System.Text.Encoding.Default.GetString(data);
MessageBox.Show("Server response was " + result);
if you´re still having problems..my server Code:
public class tcpServer
{
public void method()
{
TcpListener server = new TcpListener(IPAddress.Any, 9999);
server.Start();
TcpClient client = server.AcceptTcpClient();
NetworkStream ns = client.GetStream();
byte[] hello = new byte[100];
hello = Encoding.Default.GetBytes("hello world");
while (client.Connected)
{
ns.Write(hello, 0, hello.Length);
}
}
}
I am creating client-server app.
Server Code:
public sealed class SslTcpServer {
static X509Certificate serverCertificate = null;
public static void RunServer(string certificate) {
serverCertificate = new X509Certificate2(certificate, "123", X509KeyStorageFlags.MachineKeySet);
TcpListener listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 56748);
listener.Start();
while (true) {
Console.WriteLine("Waiting for a client to connect...");
TcpClient client = listener.AcceptTcpClient();
ProcessClient(client);
}
}
static void ProcessClient(TcpClient client) {
SslStream sslStream = new SslStream(client.GetStream());
try {
sslStream.AuthenticateAsServer(serverCertificate,
clientCertificateRequired: false,
checkCertificateRevocation: true);
sslStream.ReadTimeout = 5000;
sslStream.WriteTimeout = 5000;
Console.WriteLine("Waiting for client message...");
string messageData = ReadMessage(sslStream);
Console.WriteLine("Received: {0}", messageData);
byte[] message = Encoding.UTF8.GetBytes("Hello from the server.<EOF>");
Console.WriteLine("Sending hello message.");
sslStream.Write(message);
} catch (AuthenticationException e) {
Console.WriteLine("Exception: {0}", e.Message);
if (e.InnerException != null) {
Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
}
Console.WriteLine("Authentication failed - closing the connection.");
sslStream.Close();
client.Close();
return;
} finally {
sslStream.Close();
client.Close();
}
}
static string ReadMessage(SslStream sslStream) {
byte[] buffer = new byte[2048];
StringBuilder messageData = new StringBuilder();
int bytes = -1;
do {
bytes = sslStream.Read(buffer, 0, buffer.Length);
Decoder decoder = Encoding.UTF8.GetDecoder();
char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
decoder.GetChars(buffer, 0, bytes, chars, 0);
messageData.Append(chars);
if (messageData.ToString().IndexOf("<EOF>") != -1)
break;
} while (bytes != 0);
return messageData.ToString();
}
public static int Main(string[] args) {
string certificate = "server.crt";
RunServer(certificate);
return 0;
}
}
Client Code:
public class SslTcpClient {
private static Hashtable certificateErrors = new Hashtable();
public static bool ValidateServerCertificate(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors) {
if (sslPolicyErrors == SslPolicyErrors.None)
return true;
Console.WriteLine("Certificate error: {0}", sslPolicyErrors);
return false;
}
public static void RunClient(string machineName, string serverName) {
TcpClient client = new TcpClient("127.0.0.1", 56748);
Console.WriteLine("Client connected.");
SslStream sslStream = new SslStream(
client.GetStream(),
false,
new RemoteCertificateValidationCallback(ValidateServerCertificate),
null
);
try {
sslStream.AuthenticateAsClient("127.0.0.1");
} catch (AuthenticationException e) {
Console.WriteLine("Exception: {0}", e.Message);
Console.WriteLine(e.StackTrace);
if (e.InnerException != null) {
Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
}
Console.WriteLine("Authentication failed - closing the connection.");
client.Close();
return;
}
byte[] messsage = Encoding.UTF8.GetBytes("Hello from the client.<EOF>");
sslStream.Write(messsage);
sslStream.Flush();
string serverMessage = ReadMessage(sslStream);
Console.WriteLine("Server says: {0}", serverMessage);
client.Close();
Console.WriteLine("Client closed.");
}
static string ReadMessage(SslStream sslStream) {
byte[] buffer = new byte[2048];
StringBuilder messageData = new StringBuilder();
int bytes = -1;
do {
bytes = sslStream.Read(buffer, 0, buffer.Length);
Decoder decoder = Encoding.UTF8.GetDecoder();
char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
decoder.GetChars(buffer, 0, bytes, chars, 0);
messageData.Append(chars);
if (messageData.ToString().IndexOf("<EOF>") != -1) {
break;
}
} while (bytes != 0);
return messageData.ToString();
}
public static int Main(string[] args) {
string serverCertificateName = "127.0.0.1";
string machineName = "127.0.0.1";
SslTcpClient.RunClient(machineName, serverCertificateName);
return 0;
}
}
I had already created SSL certificate "server.crt", but I cannot connect user to server.
I have an Unhandled Exception:
System.NotSupportedException: The server mode SSL must use a certificate with the associated private key.
The exception is telling you that you need the private key also of the server certificate as the SSL server needs to have it to decrypt the session key generated by the client. Now, having said that, the certificate you are passing to the RunServer method is Server.crt which is a public cert only (i.e. it does not have associated private key). If you have generated this certificate by yourself you should also generate a server.p12 or server.pfx file (which has private key also in it) and then create a X509Certificate out of it. Something like this ..
var certificate = new X509Certificate("server.pfx", "password_of_the_private_key");
I want to write a simple http proxy server in C#. My proxy server is already able to get requests from the client and forward them to the host. It should also be already able to forward Responses from the host to the client. However, not all requests and responses are sent correctly. I want to open simple http websites with it, but it doesn't work right now. I think the problem is that I can't just forward the requests and responses directly. Do I need to adjust them before forwarding them? Or is there a different error? Thanks in advance!
public class ProxyServer
{
private TcpListener listener;
private bool serverIsRunning;
public void Start()
{
this.listener = new TcpListener(IPAddress.Any, 5000);
this.listener.Start();
this.serverIsRunning = true;
while (this.serverIsRunning)
{
if (!listener.Pending())
{
Thread.Sleep(100);
continue;
}
TcpClient client = listener.AcceptTcpClient();
Thread session = new Thread(new ParameterizedThreadStart(StartNewClientSession));
session.Start(client);
}
}
public void Stop()
{
throw new System.NotImplementedException();
}
public void StartNewClientSession(object data)
{
TcpClient client = (TcpClient)data;
NetworkStream clientStream = client.GetStream();
while (true)
{
// Get HTTP request from client
byte[] receiveBuffer = null;
if (clientStream.CanRead && clientStream != null)
{
receiveBuffer = NetworkManager.ReadMessage(clientStream);
}
else
{
continue;
}
string request = Encoding.ASCII.GetString(receiveBuffer);
Console.WriteLine(request);
string[] splittedRequest = request.Split(new char[0]);
string host = GetHostFromRequest(splittedRequest);
if (host == string.Empty)
{
continue;
}
TcpClient server = new TcpClient(host, 80);
NetworkStream serverStream = server.GetStream();
// Forward HTTP request to server
if (serverStream.CanWrite && serverStream != null)
{
NetworkManager.SendMessage(serverStream, receiveBuffer);
}
else
{
continue;
}
// Get HTTP response from server
if (serverStream.CanRead && serverStream != null)
{
receiveBuffer = NetworkManager.ReadMessage(serverStream);
}
else
{
continue;
}
string response = Encoding.ASCII.GetString(receiveBuffer);
Console.WriteLine(response);
// Forward HTTP response to client
if (clientStream.CanWrite && clientStream != null)
{
NetworkManager.SendMessage(clientStream, receiveBuffer);
}
else
{
continue;
}
}
}
public string GetHostFromRequest(string[] request)
{
for (int i = 0; i < request.Length; i++)
{
if (request[i] == "Host:")
{
string[] checkHost = request[i + 1].Split(':');
if (checkHost.Length != 1)
{
return checkHost[0];
}
else
{
return request[i + 1];
}
}
}
return string.Empty;
}
}
public class NetworkManager
{
public static byte[] ReadMessage(NetworkStream stream)
{
byte[] receiveBuffer = new byte[8192];
if (stream.CanRead && stream != null)
{
int receivedBytes = stream.Read(receiveBuffer, 0, receiveBuffer.Length);
}
return receiveBuffer;
}
public static void SendMessage(NetworkStream stream, byte[] sendBuffer)
{
if (stream.CanWrite && stream != null)
{
stream.Write(sendBuffer, 0, sendBuffer.Length);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using System.Net;
using System.Net.Sockets;
namespace BLHClient
{
class chCon
{
static TcpClient clientCon;
static NetworkStream stream;
public static bool currentlyConnected;
static bool rDHasLoopedOnce = false;
static string buffer = "";
Thread retrieveData;
string ip = "";
int port = 0;
public chCon(string ipAddress, int portNumber)
{
ip = ipAddress;
port = portNumber;
connectToConsole();
}
public void connectToConsole()//mitigates the connection
{
if (ip.Trim() == "")
ip = "127.0.0.1";
if (port == 0)
port = 2647;
try
{
clientCon = new TcpClient(ip, port);
stream = clientCon.GetStream();
//sendData("#101"); //first bit of data is sent on accepted client
retrieveData = new Thread(receiveData_Stage1);
retrieveData.Start();
}
catch (Exception e) // if the connection being naughty ;)
{
MessageBox.Show("Exception caught:\n" + e);
}
}
public void disconnectFromConsole()
{
try
{
if (clientCon.Connected || clientCon.Connected == null)
{
retrieveData.Abort();
byte[] msg = System.Text.Encoding.ASCII.GetBytes("#103");
stream.Write(msg, 0, msg.Length);
stream.Close();
clientCon.Close();
}
else
{
MessageBox.Show("Cannot disconnect from a connection that has not started.");
}
}
catch (Exception ex)
{
MessageBox.Show("Error thrown during disconnection - UNKNOWN");
}
}
public void sendData(string data)//sends data to the server
{
Byte[] dataConv = System.Text.Encoding.ASCII.GetBytes(data);
stream.Write(dataConv, 0, dataConv.Length);
}
public static void receiveData_Stage1() //builds a buffer through a loop
{
try
{
while (true)
{
Byte[] response = new Byte[256];
string responseData = String.Empty;
// Read the first batch of the TcpServer response bytes.
Int32 bytes = stream.Read(response, 0, response.Length);
responseData = System.Text.Encoding.ASCII.GetString(response);
if (responseData.Trim() == "\0")
responseData = "";
if (responseData.Trim() != "")
buffer = buffer + responseData + "\n";
if (rDHasLoopedOnce == false)
rDHasLoopedOnce = true;
}
}
catch
{
}
}
public string receiveData_Stage2() //requests the buffer through a return value string
{
string bufferTemp;
bufferTemp = buffer;
buffer = string.Empty;
return bufferTemp;
}
public bool isConnected()
{
return clientCon.Connected;
}
public bool hasLoopedOnce()
{
return rDHasLoopedOnce;
}
}
/*
while (true)
{
if (Program.currentlyConnected == true)
{
Thread.Sleep(100);
buffer = Program.receiveData_Stage2();
if (buffer != "")
richTxtBoxConsole.AppendText(buffer + "\n");
}
else
{
guiConsoleWriteLine("Connection is not active.");
break;
}
}
*/
}
This code above works, however for some reason whenever I call it and track it through debug, it seems to call connectToConsole() more than once. It's not as if I'm recursively calling it. What can I do?