Listen to UDP message in C# - c#

I have a software which sends/broadcasts UDP message over port 4747 and I want to get those messages on my C# application. I already used Microsoft Network Monitor and captured those UDP messages, but tried a bunch of stuff on my C# program and could not get any of those messages.
The message log in NetworkMonitor is like:
88922 00:46:57 14/11/2013 862.7592038 MM-B6DD62A 224.74.74.74 UDP UDP:SrcPort = 1053, DstPort = 7474, Length = 15 {UDP:1001, IPv4:984}
The message is being sent from one computer in network to other computers.
I was expecting some thing as simple as:
UdpClient udp = new UdpClient(7474);
udp.BeginReceive(Receive, new object());
public void Receive(IAsyncResult ar)
{
Console.WriteLine("Getting some thing...");
IPEndPoint ip = new IPEndPoint(IPAddress.Any, 7474);
byte[] bytes = udp.EndReceive(ar, ref ip);
string message = Encoding.ASCII.GetString(bytes);
Console.WriteLine(message);
}
could solve my problem, but is not capturing any thing.
Any suggestions?

Using a multicast group will only work with IPv6, which IPAddress.Any is not so that will not work. What broadcast address are you using? 255.255.255.255 tends not to work as often software, devices and firewalls indiscriminately drop such broad broadcasts, however using broadcasting to a more specific subnet usually works, e.g.:
192.168.255.255.

Related

How to get public port number of TcpListener?

I'm trying directly connect (using TCP) two devices that are behind routers implementing NAT. As I see, routers are translating port number of my devices, so port 13000 (port where my app is listening for incoming TCP connections) on my computer will have completly different value as seen publicly. In order to connect two devices, I need to know what the listener's "public port number" is.
I've created "rendezvous server" which is available publicly. Firstly, I've created TCP connection between client A and server. Server extracted port number and passed it to other clients so they could try to connect to client A. But I realized, that when I create new Tcp connection with server, my app creates new port from which it sends packets. So server extracts public port of newly created port used just for connection to that server and not public port of my listener.
So I'm trying to solve it other way. The idea is: I'm sending UDP packets with source port set to port of TcpListener. This way, theoretically, server could extract from incoming message public port of TcpListener (by getting source port from UDP datagram) and pass it to other devices in my network.
// client side
public void AdvertiseListener(IPAddress address, int port, Guid localDeviceId)
{
UdpClient client = new UdpClient(ListenerPort); // changing datagram source to port of my TcpListener
IPEndPoint remoteEP = new IPEndPoint(address, port);
_logger.LogInformation($"Advertising Tcp port to server at {address.MapToIPv4().ToString()}:{port}");
byte[] data = localDeviceId.ToByteArray();
for (int a = 0; a < 10; a++)
{
client.Send(data, data.Length, remoteEP);
}
}
// server side
public void AdvertisementsHandler()
{
AdvertisementListener = new UdpClient(ListenerPort);
AdvertisementListener.BeginReceive(new AsyncCallback(HandleAdverticement), null);
}
private void HandleAdverticement(IAsyncResult ar)
{
IPEndPoint senderIpEndPoint = new IPEndPoint(0, 0); // source address of incoming datagram
var receivedData = AdvertisementListener.EndReceive(ar, ref senderIpEndPoint);
[...]
_logger.LogInformation($"ADVERTICEMENT RECEIVED, port is {senderIpEndPoint.Port}");
try
{
AdvertisementListener.BeginReceive(new AsyncCallback(HandleAdverticement), null);
}
catch (Exception e)
{
_logger.LogError("Advertiser failed");
}
}
The problem is: my server receives not translated number for some reason. senderIpEndPoint in HandleAdverticement equals 13000 which is my private port number. It seems like my router, ironically, leaves port as it is this time. Do you have any ideas of what can I change to solve my problem?
Your TcpListener doesn't have a public port number. If a router is using NAT to change your source port number along the way, your application will not know about it. This is why port-forwarding is required when you want to make a service available to the public.
What you might be looking for is what is known as TCP hole punching. But in most cases that still requires you to have a public third-party public service that can let the two locations exchange their public endpoint information.
Alternatively Universal Plug and Play (UPnP) might allow you to request the router to port-forward automatically. But this is not something I have worked with myself.

Unable to receive known reply when broadcasting UDP datagrams over LAN using Sockets or UdpClient

I have searched for 2 days and found many, many questions/answers to what appears to be this same issue, with some differences, however none really seem to provide a solution.
I am implementing a library for controlling a DMX system (ColorKinetics devices) directly without an OEM controller. This involves communicating with an Ethernet-enabled power supply (PDS) connected to my home LAN, through a router, which drives the lighting fixtures. The PDS operates on a specific port (6038) and responds to properly formatted datagrams broadcast over the network.
I can successfully broadcast a simple DMX message (Header + DMX data), which gets picked up by the PDS and applied to connected lighting fixtures, so one-way communication is not an issue.
My issue is that I am now trying to implement a device discovery function to detect the PDS(s) and attached lights on the LAN, and I am not able to receive datagrams which are (absolutely) being sent back from the PDS. I can successfully transmit a datagram which instructs the devices to reply, and I can see the reply coming back in WireShark, but my application does not detect the reply.
I also tried running a simple listener app on another machine, which could detect the initial broadcast, but could not hear the return datagram either, however I figure this wouldn't work since the return packet is addressed to the original sender IP address.
I initially tried implementing via UdpClient, then via Sockets, and both produce the same result no matter what options and parameters I seem to specify.
Here is my current, very simple code to test functionality, currently using Sockets.
byte[] datagram = new CkPacket_DiscoverPDSRequestHeader().ToPacket();
Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint ep = new IPEndPoint(IPAddress.Parse("192.168.1.149"), 6039);
public Start()
{
// Start listener
new Thread(() =>
{
Receive();
}).Start();
sender.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
sender.EnableBroadcast = true;
// Bind the sender to known local IP and port 6039
sender.Bind(ep);
}
public void Send()
{
// Broadcast the datagram to port 6038
sender.SendTo(datagram, new IPEndPoint(IPAddress.Broadcast, 6038));
}
public void Receive()
{
Socket receiver = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
receiver.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
receiver.EnableBroadcast = true;
// Bind the receiver to known local IP and port 6039 (same as sender)
IPEndPoint EndPt = new IPEndPoint(IPAddress.Parse("192.168.1.149"),6039);
receiver.Bind(EndPt);
// Listen
while (true)
{
byte[] receivedData = new byte[256];
// Get the data
int rec = receiver.Receive(receivedData);
// Write to console the number of bytes received
Console.WriteLine($"Received {rec} bytes");
}
}
The sender and receiver are bound to an IPEndPoint with the local IP and port 6039. I did this because I could see that each time I initialized a new UdpClient, the system would dynamically assign an outgoing port, which the PDS would send data back to. Doing it this way, I can say that the listener is definitely listening on the port which should receive the PDS response (6039). I believe that since I have the option ReuseAddress set to true, this shouldn't be a problem (no exceptions thrown).
Start() creates a new thread to contain the listener, and initializes options on the sending client.
Send() successfully broadcasts the 16-byte datagram which is received by the PDS on port 6038, and generates a reply to port 6039 (Seen in WireShark)
Receive() does not receive the datagram. If I bind the listener to port 6038, it will receive the original 16-byte datagram broadcast.
Here is the WireShark data:
Wireshark
I have looked at using a library like SharpPCap, as many answers have suggested, but there appear to be some compatibility issues in the latest release that I am not smart enough to circumvent, which prevent the basic examples from functioning properly on my system. It also seems like this sort of basic functionality shouldn't require that type of external dependency. I've also seen many other questions/answers where the issue was similar, but it was solved by setting this-or-that parameter for the Socket or UdpClient, of which I have tried every combination to no avail.
I have also enabled access permissions through windows firewall, allowed port usage, and even completely disabled the firewall, to no success. I don't believe the issue would be with my router, since messages are getting to Wireshark.
UPDATE 1
Per suggestions, I believe I put the listener Socket in promiscuous mode as follows:
Socket receiver = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP);
receiver.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.HeaderIncluded, true);
receiver.EnableBroadcast = true;
IPEndPoint EndPt = new IPEndPoint(IPAddress.Parse("192.168.1.149"), 0);
receiver.Bind(EndPt);
receiver.IOControl(IOControlCode.ReceiveAll, new byte[] { 1, 0, 0, 0 }, null);
This resulted in the listener receiving all sorts of network traffic, including the outbound requests, but still no incoming reply.
UPDATE 2
As Viet suggested, there is some sort of addressing problem in the request datagram, which is formatted as such:
public class CkPacket_DiscoverPDSRequest : BytePacket
{
public uint magic = 0x0401dc4a;
public ushort version = 0x0100;
public ushort type = 0x0100;
public uint sequence = 0x00000000;
public uint command = 0xffffffff;
}
If I change the command field to my broadcast address 192.168.1.149' or192.168.255.255`, my listener begins detecting the return packets. I admittedly do not know what this field is supposed to represent, and my original guess was to just put in a broadcast address since the point of the datagram is to discover all devices on the network. This is obviously not the case, though I am still not sure the exact point of it.
Either way, thank you for the help, this is progress.
So in actuality it turns out that my issue was with the formatting of the outgoing datagram. The command field needs to be an address on the local subnet 192.168.xxx.xxx, and not 255.255.255.255... for whatever reason this was causing the packet to be filtered somewhere before getting to my application, though WireShark could still see it. This may be common sense in this type of work but being relatively ignorant as to network programming as well as the specifics of this interface it wasn't something I had considered.
Making the change allows a simple UdpClient send/receive to function perfectly.
Much thanks to Viet Hoang for helping me find this!
As you've already noted, you don't need to bind to send out a broadcast but it uses a random source port.
If you adjust your code to not bind the sender, your listener should behave as expected again:
Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
sender.EnableBroadcast = true;
Thread read_thread;
public Start()
{
// Start listener
read_thread = new Thread(Receive);
read_thread.Start();
}
The issue you've bumped into is that the operating system kernel is only delivering packets up to one socket binder (first come first serve basis).
If you want true parallel read access, you'll need to look into sniffing example such as: https://stackoverflow.com/a/12437794/8408335.
Since you are only looking to source the broadcast from the same ip/port, you simply need to let the receiver bind first.
If you add in a short sleep after kicking off the receive thread, and before binding the sender, you will be able to see the expected results.
public Start()
{
// Start listener
new Thread(() =>
{
Receive();
}).Start();
Thread.Sleep(100);
sender.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
sender.EnableBroadcast = true;
// Bind the sender to known local IP and port 6039
sender.Bind(ep);
}
Extra note: You can quickly test your udp sockets from a linux box using netcat:
# echo "hello" | nc -q -1 -u 192.168.1.149 6039 -
- Edit -
Problem Part #2
The source address of "255.255.255.255" is invalid.
Did a quick test with two identical packets altering the source ip:
https://i.stack.imgur.com/BvWIa.jpg
Only the one with the valid source IP was printed to the console.
Received 26 bytes
Received 26 bytes

Multiple UDP connections to different remote IPs with the same port

I have a need to talk to multiple devices on a private LAN using a proprietary UDP protocol. In a production setting we have a industrial PC running a C++ application that can connect to multiple devices and communicate freely with them. I am trying to duplicate that communication using C# for a windows application that technicians, testers and others would be using. I have probably done this myself a thousands times in c++ but c# seems to be giving me all sorts of fits.
I have one UDP listener listening on Any IP and specific Port. This port is different from the device command port. This receives a periodic heartbeat from each device. From this communication I am able to get the specific IP and command Port for that device. The program maintains a list of devices and displays that lists to the user. The user can then select a specific device and inspect it more for more details.
If there are several devices with the same port number the program will not be able to inspect those devices at the same time. When the user selects the device the program creates a new instance of the UdpClient. In pseudo-code form:
udpConnection = new UdpClient();
udpConnection.ExclusiveAddressUse = false;
udpConnection.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpConnection.Client.Bind(localEndpoint);
udpConnection.Client.Connect(remoteEndpoint);
Local Endpoint is the Local interface IP and the Device Port Number of the machine the application is running on. Remote EndPoint is the Device IP and Device Port that the application wants to inspect further.
As anyone had similar issues and what have you done to get around it?
Thanks in advance
Update sample network diagram and further explanation:
Network Diagram
In the image I will be able to have two windows viewing Device A and C or B and C simultaneously with no issues. However if I have Device A and C the window that I opened second will not get any communications updates until I close the first window. If I "sniff" the network with WireShark I see all the communications as I would expect.
Code Snippet:
private void ClientThread()
{
IPEndPoint myEndPoint;
myLogger = LogManager.GetLogger("ClientLogs");
myLogger.Debug("Client Started!");
IPAddress ClientAddress = System.Net.IPAddress.Parse(ClientIP);
myIP = "10.0.0.4"; // Currently hard-coded local interface IP
IPAddress thisAddress = System.Net.IPAddress.Parse(myIP);
ClientEndPoint = new IPEndPoint(ClientAddress, Convert.ToInt32(ClientPort));
myEndPoint = new IPEndPoint(thisAddress, Convert.ToInt32(ClientPort)); // Both forms launch but only the first one will receive data.
//myEndPoint = new IPEndPoint(thisAddress, 0); // Both forms will launch but no data received (packets do show being received in wireshark)
//myEndPoint = new IPEndPoint(IPAddress.Any, ClientPort); // Both forms launch but only the first one will receive data.
try
{
myUDP = new UdpClient();
myUDP.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); // "Only one usage of each socket address (protocol/network address/port) is normally permitted" Exception when removed.
myUDP.ExclusiveAddressUse = false; // No difference if this is removed
myUDP.Client.Bind(myEndPoint); // Neither form will receive data if this is removed
myUDP.Client.Connect(ClientEndPoint); // removing this will allow the forms to launch but again the only the first will receive data
}
catch (Exception ex)
{
myUDP = null;
myLogger.Fatal(String.Format("Error in setting up UDP Client: {0}", ex.Message));
return;
}
myLogger.Debug(String.Format("Attempt to connect to : {0} on {1}", ClientIP, Convert.ToInt32(ClientPort)));
byte[] bytes = new byte[1452];
try
{
while (ThreadLoop)
{
IPEndPoint newEndPoint = new IPEndPoint(IPAddress.Any, 0);
Byte[] receiveBytes = myUDP.Receive(ref newEndPoint);
ParseProtocolPacket(ref receiveBytes); // Code to parse the data received
}
}
catch (Exception Ex)
{
myLogger.Debug("Client Socket Other Error: " + Ex.Message);
}
}
I think your problem is here:
udpConnection.Client.Bind(localEndpoint);
This line, if I understand correctly, is telling it to use the same local port to make the outbound request. But you already have another UdpClient listening on that port, so Windows won't know which one to send the traffic to (or it just sends it to the first one).
You should be able to just not use Bind() here. Without it, when you call Connect(), it will assign a random local port, which is the way most outbound network requests work.
Or if you need to specify the network interface, then pass 0 for the port and Windows will assign one:
localEndpoint = new IPEndPoint(ipAddress, 0);

UdpClient doesn't receive multicast traffic upon connection

I'm using a UdpClient to receive and send multicast traffic, but I'm having a problem when a new network interface becomes operational while the application is up and running.
The UdpClient is created in my application when the interface becomes operational (plug in network cable raises NetworkChange.NetworkAddressChanged), it binds to the static IP of the interface, and the expected IGMP packets are visible in wireshark on that interface, but the UdpClient instance never reports there is any data available.
The issue also appears to be present if you create the UdpClient before the cable is connected.
I've tried setting SocketOptionName.MulticastInterface, but that should only concern sending multicast traffic, not receiving... Example for this here: https://support.microsoft.com/en-us/kb/318911
Here is a console app that exhibits this issue. While this app is running, I connect the Ethernet cable and Wireshark shows the IGMP join group packets from this app, and incoming multicast traffic from another computer. If I have the cable already plugged in and start the app, it receives all of the traffic I expect.
class Program
{
static UdpClient udpClient;
static IPAddress bindAddress = IPAddress.Parse("192.168.101.220");
static IPAddress groupListenAddress = IPAddress.Parse("239.255.0.1");
static int port = 9999;
static bool shouldRun = true;
static Thread thread;
static void Main(string[] args)
{
udpClient = new UdpClient();
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpClient.Client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, true);
IPEndPoint localEndPoint = new IPEndPoint(bindAddress, port);
udpClient.Client.Bind(localEndPoint);
udpClient.JoinMulticastGroup(groupListenAddress);
thread = new Thread(runThread);
thread.Start();
Console.WriteLine("Press Enter to exit.");
Console.ReadLine();
shouldRun = false;
thread.Join(100);
}
private static void runThread(object obj)
{
while (shouldRun)
{
if (udpClient.Available > 0)
{
IPEndPoint endPoint = null;
byte[] buffer = udpClient.Receive(ref endPoint);
Console.WriteLine("Received Message from: {0} Length: {1}", endPoint, buffer.Length);
}
Thread.Sleep(10);
}
}
}
Note that IGMP messages are sent by your host OS, not by your application. If the OS sees a join for a multicast address for the first time it will send out IGMP messages. If another process wants to join the same address as well, new IGMP message may or may not be sent.
Also all kinds of network components (in particular routers, but also Powerline adapters use IGMP snooping to find out where to send multicast traffic, and they often get it wrong. There are two incompatible versions of IGMP and some devices support only one version and some translate between versions in a strange way. This is a big mess.
To make it all really horrible, most devices, including your local host OS, have a time dependent behavior. This makes analyzing problems really difficult since you can never draw hard conclusions, because at the moment it may work just by chance.
Independent of IGMP, the bind() statement is confusing for UDP. On Linux bindign to an IP address will filter all incoming UDP packets and you will only receive packets going to this specific IP address. To receive multicast traffic on Linux you usually have to bind to 0.0.0.0. But I assume you are using Windows, where binding to an IP address of a local adapter is the right thing. Then you will receive mutilcast traffic going to this adapter.

When receiving UDP packets, the port does not match the listen port

This isn't a problem as much as it is a curiosity. I created a simple send/receive C# application using UDP, mostly following the MSDN examples on UdpClient. I have a textbox acting as a log for when things are sent or received; it prints the timestamp and what was sent/received from where.
The curiosity comes in with the port numbers. When the program is listening on some port and it receives a packet, the port on the packet received doesn't match up with the port it was listening on.
For example, here's a screenshot of the application (note: this still happens even if using different computers to send/receive):
It's receiving the packets just fine, which is why this isn't really a "problem" because it is working. I'm just curious why the port on the received packets is showing different than the port it is listening on. I'm wondering if perhaps it's just garbage data?
Here's the code that runs when data is received (using the AsyncCallback that I picked up from MSDN):
private void ReceiveCallback(IAsyncResult ar)
{
try {
// Pull the socket from the AsyncResult parameter
UdpState state = (UdpState)(ar.AsyncState);
UdpClient udp = state.udp;
IPEndPoint end = state.endpoint;
// Grab and convert the message into a string
byte[] recvBytes = udp.EndReceive(ar, ref end);
string recvString = Encoding.ASCII.GetString(recvBytes);
/* Here's where it's logging the IPEndPoint onto the console.
* Is the port meaningless when receiving a packet, and that's why it's
* always something random? Or is there some meaning to it that I'm
* unaware of? */
ConsoleLog(end.ToString() + " Recv: " + recvString);
// Start the listen cycle again so this will be called again
listener.BeginReceive(new AsyncCallback(ReceiveCallback), state);
} catch (ObjectDisposedException) {
// Do nothing - Expected error when the UDP Listener is closed.
}
}
Is the port number when receiving packets just meaningless garbage data, or does it have some sort of use?
Every UDP packet has a source and destination ip address and port, what you are seeing is the source port address.
A well known port is used to send data to, the machine sending data assigns a free port to the source port of the packet so that it can receive data from the server on that port.
There's a port number at each end of the connection: the published port number that your process is listening on, and the originating (client) port number (which could be on a different machine).

Categories