C# Getting sender address from UDP message - c#

I have an embedded Ethernet interface (Lantronix XPort) that responds to a UDP broadcast with its identifying information.
I am able to multicast the "magic packet" and datagrams are received by the listener correctly, however I also need to find out what IP Address send that response datagram. If it were TCP, I would do socket.RemoteEndPoint, but that throws an exception when applied to a UDP socket.
public class Program
{
public static void Main(string[] args)
{
// magic packet
byte[] magicPacket = new byte[4] { 0, 0, 0, 0xf6 };
// set up listener for response
Socket sendSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
// EDIT: Also, had to add this to for it to broadcast correctly
sendSocket.EnableBroadcast = true;
IPEndPoint listen_ep = new IPEndPoint(IPAddress.Any, 0);
sendSocket.Bind(listen_ep);
// set up broadcast message
EndPoint send_ep = new IPEndPoint(IPAddress.Parse("192.168.255.255"), 30718);
sendSocket.SendTo(magicPacket, magicPacket.Length, SocketFlags.None, send_ep);
DateTime dtStart = DateTime.Now;
while (true)
{
if (sendSocket.Available > 0)
{
byte[] data = new byte[2048];
// throws SocketException
//IPEndPoint ip = sendSocket.RemoteEndPoint as IPEndPoint;
sendSocket.Receive(data, SocketFlags.None);
if (data.Length > 4)
{
PrintDevice(data);
}
}
if (DateTime.Now > dtStart.AddSeconds(5))
{
break;
}
Console.WriteLine(".");
Thread.Sleep(100);
}
// wait for keypress to quit
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
Any thoughts? Is there a better strategy to reading the response datagrams that would let me ascertain the Remote IP Address?
EDIT:
As is typical, the minute I post on SO, a moment of clarity hits me.
Turns out I can just do this:
EndPoint remote_ep = new IPEndPoint(IPAddress.Any, 0);
// Use ReceiveFrom instead of Receieve
//sendSocket.Receive(data, SocketFlags.None);
sendSocket.ReceiveFrom(data, ref remote_ep);
And remote_ep now contains the remote endpoint information!

Take a look at ReceiveFrom instead of Receive, it will let you pass in a reference to an Endpoint.

What about Asynchronous socket?I didn't find any way to get the remote IP address. (Asynchronous method ReceiveFromAsync is my only option in wp8)

EndPoint remote_ep = new IPEndPoint(IPAddress.Any, 0); // Use ReceiveFrom instead of
sendSocket.Receive(data, SocketFlags.None);
sendSocket.ReceiveFrom(data, ref remote_ep);
i think it works for IP but it fails for port number
if you would notice
try chaging 0 to something else like 6530 4expl
it system will would generate it's random port number
Any ideas to why is it ?
P.S. Any ideas how can i change my user name here .... ?
FOUND IT : the abstract class only needed for representation of port it is in value not out
since there's no bind done before hand this operation ref EndPoint needed to represent the sender. Meaning that it is there to show senders port and IP not to specify from where to get the communication. And EndPoint instantiation is really just a formality seems like it is overriden by system with senders address anyway. I think it has to do somethign with the way UDP protocol works.
But all in all the ref EndPoint is there only shows where u got the packet from and only it does not specify where u want u'r commuicatino to be from.

Related

How to detect destination IP address from UDP packets using UDPClient Class

I am working on the application which send and receive messages on UDP between client app and server app.
On my server I have 4 different network cards, e.g. nic1 = 169.524.15.12, nic2 = 169.524.15.65, etc. My DNS is point to nic2. The client app resolves the DNS and send data to nic2. However my server app sometime respond to client from nic1.
I'm using an UdpClient to listen for incoming packets.
This is my server application code:
objSocketServer = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
EndPoint objEndPointOfServer = new IPEndPoint(IPAddress.Any, 5000);
objSocketServer.Bind(objEndPointOfServer);
objSocketServer.BeginReceiveFrom(_arrReceivedDataBuffer, 0, BUFSIZE - 1, SocketFlags.None, ref objEndPointOfServer, DoReceiveFromClient, objSocketServer);
private void DoReceiveFromClient(IAsyncResult objIAsyncResult)
{
try
{
// Get the received message.
_objSocketReceivedClient = (Socket)objIAsyncResult.AsyncState;
EndPoint objEndPointReceivedClient = new IPEndPoint(IPAddress.Any, 0);
// Received data.
int intMsgLen = _objSocketReceivedClient.EndReceiveFrom(objIAsyncResult, ref objEndPointReceivedClient);
byte[] arrReceivedMsg = new byte[intMsgLen];
Array.Copy(_arrReceivedDataBuffer, arrReceivedMsg, intMsgLen);
// Client port.
// Get and store port allocated to server1 while making request from client to server.
int _intClientServer1Port = ((IPEndPoint)objEndPointReceivedClient).Port;
// Send external ip and external port back to client.
String strMessage = ((IPEndPoint)objEndPointReceivedClient).Address.ToString() + ":" + _intClientServer1Port.ToString();
byte[] arrData = Encoding.ASCII.GetBytes(strMessage);
objSocketServer.SendTo(arrData, arrData.Length, SocketFlags.None, objEndPointReceivedClient);
// Start listening for a new message.
EndPoint objEndPointNewReceivedClient = new IPEndPoint(IPAddress.Any, 0);
objSocketServer.BeginReceiveFrom(_arrReceivedDataBuffer, 0, _arrReceivedDataBuffer.Length, SocketFlags.None, ref objEndPointNewReceivedClient, DoReceiveFromClient, objSocketServer)
}
catch (SocketException sx)
{
objSocketServer.Shutdown(SocketShutdown.Both);
objSocketServer.Close();
}
}
}
Is there any way so that in code, I can detect that I have received packet on which IP address on server and revert with the response with same IP?
Arguably, I could resolve DNS in server app as well and make sure that my server app only listen to IP on which client app is sending packets, however that approach will not work for me when my server app have to listen on > 1 IP.
The SendTo command will use the appropriate NIC (aka, local interface) for the destination address provided. The system metrics determine that. It's not something you set in your code. To view the system metrics, run the command netstat -rn and look at the Interface column. You many need to adjust those if you have a tie. You can enumerate them in code as well using GetAllNetworkInterfaces() and bind to a specific one (if that is what you wanted).

Sending/receiving UDP packets on thousands of port numbers

I have a set of requirements for a client/server application as listed below:
1) Program sends a statuscheck message to a host which is listening on a predefined UDP port. This message is sent on a source port number given by the OS.
2) The program needs to listen on the source port number initiated in step 1 to receive the response from the remote host. The program therefore must listen on thousands of port at the same time.
3) This process needs to be done for thousands of hosts per minute
Below I've created a sample example that sends a large number of requests to an Echo Server to mimic this behaviour. The problem that I'm facing is that although I close each socket after receiving data from the remote host, after about 16,000 requests an exception is thrown saying system lacked sufficient buffer space or queue was full.
What would be a way to achieve such requirements?
public void SendChecks()
{
IPEndPoint ip = new IPEndPoint(IPAddress.Parse("1.1.1.1"), 7);
for (int i = 0; i < 200000; i++)
{
Socket _UdpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
stateobject so = new stateobject(_UdpSocket);
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
EndPoint tempRemoteEP = (EndPoint)sender;
_UdpSocket.Bind(tempRemoteEP);
string welcome = "Hello";
byte[] data = new byte[5];
data = Encoding.ASCII.GetBytes(welcome);
_UdpSocket.BeginSendTo(data, 0, data.Length, SocketFlags.None, ip, new AsyncCallback(OnSend), _UdpSocket);
//Start listening to the message send by the user
EndPoint newClientEP = new IPEndPoint(IPAddress.Any, 0);
_UdpSocket.BeginReceiveFrom(so.buffer, 0, so.buffer.Length, SocketFlags.None, ref newClientEP, new AsyncCallback(DoReceiveFrom), so);
}
}
private void DoReceiveFrom(IAsyncResult ar)
{
try
{
stateobject so = (stateobject)ar.AsyncState;
Socket s = so.sock;
// Creates a temporary EndPoint to pass to EndReceiveFrom.
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
EndPoint tempRemoteEP = (EndPoint)sender;
int read = s.EndReceiveFrom(ar, ref tempRemoteEP);
so.sb.Append(Encoding.ASCII.GetString(so.buffer, 0, read))
//All the data has been read, so displays it to the console.
string strContent;
strContent = so.sb.ToString();
Console.WriteLine(String.Format("Read {0} byte from socket" +"data = {1} ", strContent.Length, strContent));
s.Close();
s.Dispose();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
private void OnSend(IAsyncResult ira)
{
Socket s = (Socket)ira.AsyncState;
Console.WriteLine("Sent Data To Sever on port {0}",((IPEndPoint)s.LocalEndPoint).Port);
s.EndSend(ira);
}
}
I think the best way to go in terms of performance and simplicity would be to simply use a single port number anywhere between:
1025 - 65553
Then when listening for thousands of messages from other peers they also send to a predefined known port number and you can process them asynchronously.
To listen to a known port number, in this case 60000:
mySocket.Bind(new IPEndPoint(IPAddress.Any, 60000));
Also do not close the socket after each operation! Keep it open and re-use it.
Properly written it would be walk in the park for .Net and the OS to handle your requirements.

SocketException An existing connection was forcibly closed by the remote host

I've decided to take a look at network messaging etc and my first port of call was UDP.
The problem i have is when i attempt to send a message. I'm trying to hit an IP on a specifc port, but the application errors with the error
"SocketException An existing connection was forcibly closed by the remote host".
Here is the code.
User ME = new User();
UdpClient MyUDPClient;
private void Form1_Load(object sender, EventArgs e)
{
ME.Username = Environment.UserName;
}
private void StartUDP_Click(object sender, EventArgs e)
{
CreateUDPClient();
}
private void CreateUDPClient()
{
IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
foreach (IPAddress ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
int Port = int.Parse(txt_Port.Text);
ME.UserIP = new IPEndPoint(ip, Port);
break;
}
}
MyUDPClient = new UdpClient(ME.UserIP);
UDPListening();
}
public void UDPListening()
{
MyUDPClient.BeginReceive(ReceiveMessage, new object());
}
private void ReceiveMessage(IAsyncResult IAR)
{
byte[] B = MyUDPClient.EndReceive(IAR, ref ME.UserIP);
ProcessMSG(Encoding.ASCII.GetString(B));
UDPListening();
}
delegate void MessageDelegate(String MSG);
public void ProcessMSG(String M)
{
if (this.lbl_Messages.InvokeRequired)
{
MessageDelegate Del = new MessageDelegate(ProcessMSG);
this.Invoke(Del, M);
}
else
{
lbl_Messages.Text = M;
}
}
//Send Data to Another version of this program elsewhere.
private void btn_SendtoTarget_Click(object sender, EventArgs e)
{
IPEndPoint TargetIP = new IPEndPoint(IPAddress.Parse(txt_Send2IP.Text),int.Parse(txt_Send2Port.Text));
byte[] Message = Encoding.ASCII.GetBytes("TEST TEST TEST");
MyUDPClient.Send(Message, Message.Length, TargetIP);
}
}
thanks for the help.
Not sure if this helps but...
The Application is running on machine which is set to listen is on 192.168.0.25:5555
the Send is trying to send to Machine 192.168.0.50:10001
T
From further reading, I think my specific issue is the creation of the UDPclient object. It is created and is then listening on the ip 192.168.0.25:5555. When i attempt to send a message I'm attempting to use the same UDPClient but sending to a new IP. I'm getting the vibe that this is not the correct procedure and thus its trying to close the previous down??? I'm sure someone can comfirm this. So that would suggest to me that to have effective UDP networking (UP and Down) i'd need to have a UDPclient receiving and a second UDP to be able to send (which is dynamic to each target address i want to hit). Once again this is all guess work, and if i have this i hope someone could provide some pointers.
Several problems above.
Don't use ME in C#, it is this. Me is VB. The code above would not compile, as written, if using C#, since you left out your User() class you define as ME. I am not sure why you think you need that, since all it seems to hold is UserIP and UserName. The IP is part of a Socket, so you should just use that if you ever needed it:
IPAddress ip = IPAddress.Parse(socket.RemoteEndPoint);
And UserName could be made a global string variable - doesn't have to be part of a class.
Maybe I'm being nitpicky, but I didn't see where it was required to have either of those variables in the User() object like that and just mucked things up, for me, trying to decipher the code.
Always define your Socket, connect to it, then do your .Send(). You are missing the first 2 steps in your button click - you just do your .Send(). UdpClient is not a Socket, and I think it's better to do this as a Socket and define your connection type later. I think you could be right that you are trying to do your .Send() using the UdpClient you defined as your listener. Don't use the same object for your send and your listening! Normally you would, but you have 2 different addresses and ports for each event.
Don't use a foreach in your CreateUDPClient() function to get your IPAddress to assign to your IPEndPoint. You already knew your IP. Assign it directly. It's wasting processing time.
IPAddress ip = IPAddress.Parse("192.168.0.25");
IPEndPoint endPoint = new IPEndPoint(ip, port);
If you only had the host name, you would do:
string hostName = "MyComputerName";
int port = 5555; // or int.Parse(txt_Port.Text); ???
IPHostEntry hostEntry = Dns.GetHostAddresses(hostName);
IPEndPoint endPoint = new IPEndPoint(hostEntry[0], port);
Don't use Dns.GetHostEntry() -- if there's no reverse-lookup (PTR) record for that name, it will fail. Use Dns.GetHostAddresses(). And I have no idea why you think you needed the loop unless you have IPv6 addresses for the same host name you were providing. If not, just use [0] - it should be the first and only IP that will be returned that you'll be using if not using IPv6. But again, since you already have the IP, just plug that in - no need to do the lookup. It helps you eliminate Dns.GetHostName(), too - just use 192.168.0.25.
For your reference, MSDN has a procedure for your synchronous socket send/receive here:
https://msdn.microsoft.com/en-us/library/kb5kfec7(v=vs.110).aspx
and asynchronous socket send/receive here:
http://msdn.microsoft.com/en-us/library/bew39x2a(v=vs.110).aspx
Since I despise link only answers, and you seem to be mixing these 2 methods by using Send() and EndReceive(), respectively to the links above, I will endeavor to describe its contents succinctly and help fix your code:
Basically they say to use a StateObject class, instead of the global variable MyUDPClient you have:
public class StateObject
{
public byte[] buffer = new byte[1024];
public Socket workSocket;
public StringBuilder sb = new StringBuilder();
}
You would create a socket and add it to that. Buffer serves as a way to tell the Receive() or EndReceive() the size of the chunk you want to read back from the response at one time, and sb will serve as a placeholder for the response.
It looks like you have a lot going on here: a SendtoTarget_Click to do a one-off test from the form, and your listener. Your SendtoTarget button does a synchronous send, your StartUDP_Click() does an asynchronous receive.
You would change your SendtoTarget_Click() event to be this (which never defined your socket, before, and you must connect to it before sending):
private void btn_SendtoTarget_Click(object sender, EventArgs e)
{
IPEndPoint TargetIP = new IPEndPoint(IPAddress.Parse(txt_Send2IP.Text),int.Parse(txt_Send2Port.Text));
byte[] Message = Encoding.ASCII.GetBytes("TEST TEST TEST");
// Create a UDP socket.
Socket sender = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Udp);
try
{
// Connect to the remote endpoint.
sender.Connect(TargetIP);
// Send message -- already contains the endpoint so no need to
// specify again
sender.Send(Message, 0, Message.Length, SocketFlags.None);
sender.Close();
}
catch (Exception)
{
// do something here...
}
}
For your listener, you can do:
private void CreateUDPClient()
{
IPEndPoint TargetIP = new IPEndPoint(IPAddress.Parse("192.168.0.25"), 5555);
// Create a UDP socket.
Socket receiver = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Udp);
try {
// Create the state object.
StateObject state = new StateObject();
state.workSocket = receiver;
// Begin receiving the data from the remote device.
receiver.BeginReceive(state.buffer, 0, 256, 0,
new AsyncCallback(ReceiveMessage), state);
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}
and your function called ReceiveMessage(), does this:
private void ReceiveMessage(IAsyncResult IAR)
{
string response = String.Empty;
try {
// Retrieve the state object and the client socket
// from the asynchronous state object.
StateObject state = (StateObject) IAR.AsyncState;
Socket client = state.workSocket;
// Read data from the remote device.
int bytesRead = client.EndReceive(IAR);
if (bytesRead > 0) {
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
// Get the rest of the data.
client.BeginReceive(state.buffer, 0, 256, 0,
new AsyncCallback(ReceiveCallback), state);
} else {
// All the data has arrived; put it in response.
if (state.sb.Length > 1) {
response = state.sb.ToString();
}
// Signal that all bytes have been received.
client.Close();
}
ProcessMSG(response);
CreateUDPClient(); // personally, I would re-create than calling BeginReceive directly
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}
Did my best to integrate your code with MSDN's in a way that should work. You might be able to get away with assigning that socket to the StateObject and calling BeginReceive() on it, again - not sure. But don't re-use the UdpClient object like that. Use the StateObject class like on MSDN and use it ONLY as your listener.

Unable to read incoming responses using raw sockets

I am trying to read a response from a website via code by listening to a raw socket, though so far I've only been able to read the outgoing requests sent by my computer rather than the incoming responses that I'm actually interested in.
How might I go about reading the incoming responses?
EDIT: Using Wireshark I've come to find that the data I'm looking for is being sent via TCP, I believe.
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Unspecified);
IPAddress localIP = Dns.GetHostByName(Dns.GetHostName()).AddressList[0];
listener.Bind(new IPEndPoint(localIP, 0));
byte[] invalue = new byte[4] { 1, 0, 0, 0 };
byte[] outvalue = new byte[4] { 1, 0, 0, 0 };
listener.IOControl(IOControlCode.ReceiveAll, invalue, outvalue);
while (true)
{
byte[] buffer = new byte[1000000];
int read = listener.Receive(buffer);
if (read >= 20)
{
Console.WriteLine("Packet from {0} to {1}, protocol {2}, size {3}",
new IPAddress((long)BitConverter.ToUInt32(buffer, 12)),
new IPAddress((long)BitConverter.ToUInt32(buffer, 16)),
buffer[9],
buffer[2] << 8 | buffer[3]
);
}
}
port 0 says he will listen on all ports, i think you need to set ProtocolType.Unspecified to ProtocolType.IP instead.
new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Raw);
is for ipv6 from what i read on msdn only ProtocolType.IP is supported for ipv4 with raw sockets.
Also im thinking this is a connectionless socket right?
Reciveall wouldnt really have an affect unless thats the case.
if youre after the ip header u can get it by setting up the code like this:
Socket sck = new Socket( AddressFamily.InterNetwork , SocketType.Raw , ProtocolType.IP);
sck.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.HeaderIncluded, true);
hope this helps :)
I had a similar problem in my C++ program using basically the same raw sockets setup. In my case I can see incoming packets in the debug build, but not in a release build. Outgoing packets are seen in both builds. I'm not sending any packets in this program.
I'm building with VS2008 native C++ under Win7 x64.
My issue was with the firewall. When the project was created in VS it apparently put an "Allow" entry in the firewall for network access by the project build, but only for the debug build of the program.
I had to add another entry for the release build and this then allowed incoming packets. The advance firewall settings under Win7 can also cause specific protocols to be blocked, so if you're getting only partial incoming messages check those settings for your program's entry.
Today I was wondering how to do the exact same thing! Here is my code which now seems to work, credit for getting this working is due to fellow answerer 'Tom Erik' for suggesting ProtocolType.IP.
static void Main(string[] args)
{
// Receive some arbitrary incoming IP traffic to an IPV4 address on your network adapter using the raw socket - requires admin privileges
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP);
IPAddress ipAddress = Dns.GetHostEntry(Dns.GetHostName()).AddressList
.Where((addr) => addr.AddressFamily == AddressFamily.InterNetwork)
.Where((addr) => addr.GetAddressBytes()[0] != 127)
.First();
s.Bind(new IPEndPoint(ipAddress, 0));
byte[] b = new byte[2000];
EndPoint sender = new IPEndPoint(0, 0);
int nr = s.ReceiveFrom(b, SocketFlags.None, ref sender);
}

DNS relay UDP on port 53

I noticed that BT Home are sending back fake DNS results from their DNS servers and this allows sites to bypass the IP addresses i have blocked in the firewall so i was looking to create my own DNS relay/server.
So far i can receive request on UDP port 53 and send them off to the DNS server and get a valid byte[] stream result and i then send back to the browser using the remote client port the request was made on but the browser just sends the request back again.
I've tested the code from a socket and the results work OK but for some reason IE/FF simply will not except the results.
public void Listen()
{
receiveSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp );
receiveEndPoint = new IPEndPoint(IPAddress.Any, receivePort); receiveSocket.Bind(receiveEndPoint);
receivePort = (receiveSocket.LocalEndPoint as IPEndPoint).Port;
receiveBuffer = new byte[BufferSize];
receiveAsyncResult = receiveSocket.BeginReceiveFrom(receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None, ref receiveEndPoint, new AsyncCallback(NetworkMessageReceivedCallback), receiveSocket);
}
public void NetworkMessageReceivedCallback(IAsyncResult asyncResult)
{
EndPoint remoteEndPoint = null;
byte[] bytes = null;
remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); //Will contain the clients port
int bytesRead = receiveSocket.EndReceiveFrom(asyncResult, ref remoteEndPoint);
bytes = new Byte[bytesRead];
Buffer.BlockCopy(receiveBuffer, 0, bytes, 0, bytesRead);
//string ip = "208.67.222.222";
string ip = "192.168.1.254";
IPAddress dnsServer = IPAddress.Parse(ip);
Response R = Resolver.Lookup(bytes, dnsServer);
receiveSocket.SendTo(R.Message , remoteEndPoint);//127.0.0.1
receiveSocket.Close();
Listen();
}
I never dealt with raw DNS from C# but it looks like you are trying to resolve the bytes you received from the client, instead of just relaying them to the DNS server.
The message you read off the UDP socket contains a DNS query, not just a host name. Take a look at the RFC 2929 for what goes in there.
You might be interested in this little but great DNS filter - adsuck - by Marco Peereboom (though it's for Unix, not Windows).
Also, shouldn't your try and listen to UDP and TCP. I think UDP is used mostly for authoritative DNS queries.

Categories