Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Getting the IP Address of the client which the UDP server socket received data from

I have a very strange problem. I'm not able to find the IP Address of the client which my server receives data from. Below is my UDP Listener class.

The IPPacketInformation does not contain the IP. The clientEndPoint which I reference in my EndReceiveMessageFrom does neither.

When I

Console.Writeline(((IPEndPoint)clientEndPoint).Address); 

I get the IP Address of the server. I have the server hosted on my own machine so I get my own IP Address. When I try to access clientEndPoint.remoteEndPoint it throws an error because the socket isn't connected (due to being UDP).

So basically, a client from an external IP is able to send data, but I can't answer the client since I'm not able to retrieve it's IP. Any help is appreciated!

public class UdpListener
{
    private Socket s;
    public byte[] ReceiveBuffer = new byte[2048];

    public UdpListener()
    {
        s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.PacketInformation, true);
        s.Bind(new IPEndPoint(IPAddress.Any, 36200));
    }

    public void Listen()
    {
        try
        {
            EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
            s.BeginReceiveMessageFrom(ReceiveBuffer, 0, ReceiveBuffer.Length, SocketFlags.None, ref remoteEndPoint, Recv, s);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            throw;
        }
    }

    private void Recv(IAsyncResult res)
    {
        try
        {
            Socket receiveSocket = (Socket)res.AsyncState;

            EndPoint clientEndPoint = new IPEndPoint(IPAddress.Any, 0);
            IPPacketInformation packetInfo;
            SocketFlags flags = SocketFlags.None;
            int udpMessageLength = receiveSocket.EndReceiveMessageFrom(res, ref flags, ref clientEndPoint, out packetInfo);
            byte[] udpMessage = new byte[udpMessageLength];
            Array.Copy(ReceiveBuffer, udpMessage, udpMessageLength);

            Console.WriteLine(
                "{0} bytes received from {1} to {2}",
                ReceiveBuffer,
                clientEndPoint,
                packetInfo.Address
            );

            EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, ((IPEndPoint)receiveSocket.LocalEndPoint).Port);
            s.BeginReceiveMessageFrom(ReceiveBuffer, 0, ReceiveBuffer.Length, SocketFlags.None, ref remoteEndPoint, Recv, s);

            //Process data
            RaiseDataReceived(new ReceivedDataArgs(packetInfo.Address, ((IPEndPoint)clientEndPoint).Port, udpMessage));
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            throw;
        }
    }

    public delegate void DataReceived(ReceivedDataArgs args);

    public event DataReceived DataReceivedEvent;

    private void RaiseDataReceived(ReceivedDataArgs args)
    {
        DataReceivedEvent?.Invoke(args);
    }
}

I've tried to disable my firewall but that does not help. I've also done Port Forwarding on my router thus I can receive data from external clients.

EDIT to clarify the problem:

Server hosted on my machine behind a NAT with public IP 214.214.214.214.

The client is another machine, behind another NAT with public IP 910.910.910.910.

The client sends a message to the server, server receives it and able to read the content. When server get the IPEndPoint of the client, the displayed IP is 214.214.214.214 (IP of the server, not the Client)

EDIT Maybe I should say that I wasn't able to receive messages from clients on external networks until I ordered a "Dynamic IP" from my ISP. Still can't get the public IP of the source.

EDIT When using Wireshark and sniff a packet sent from external client to my server I can see it's the wrong src IP as well. In the picture below the src IP is my server IP and not the IP of the client that sent the data.

enter image description here

like image 724
MatMat Avatar asked Sep 04 '18 10:09

MatMat


People also ask

What C is used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

Is C language easy?

C is a general-purpose language that most programmers learn before moving on to more complex languages. From Unix and Windows to Tic Tac Toe and Photoshop, several of the most commonly used applications today have been built on C. It is easy to learn because: A simple syntax with only 32 keywords.

What is the full name of C?

In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr. Stroustroupe.

Is C programming hard?

C is more difficult to learn than JavaScript, but it's a valuable skill to have because most programming languages are actually implemented in C. This is because C is a “machine-level” language. So learning it will teach you how a computer works and will actually make learning new languages in the future easier.


2 Answers

After several days of reading everything I possibly could on routers, network and writing different examples of Receive, ReceiveFrom, ReceiveMessageFrom, BeginReceive, BeginReceiveFrom, BeginReceiveMessageFrom, and ReceiveAsync - I've solved my issue.

I changed my router. I can now get the source IP of the external client using a very old router. The router I was using before was a new Docsis 3.1.

Why it works with an old router, I don't know, but for some reason, the Docsis 3.1 changed the source IP to its own IP before letting the UDP message to my machine.

like image 160
MatMat Avatar answered Sep 18 '22 17:09

MatMat


With using the UdpClient class you can actually retrieve the remote endpoint when receiving a message.

I have used a solution like the following to solve this task:

public void StartServer()
{
    var udpServer = new UdpClient(new IPEndPoint(IPAddress.Any, ConnectionInformation.DETECTION_PORT));
    udpServer.BeginReceive(new AsyncCallback(detectionCallback), udpServer);
}

private void detectionCallback(IAsyncResult ar)
{
    var client = (ar.AsyncState as UdpClient);
    if (client.Client == null) return;

    var endPoint = new IPEndPoint(IPAddress.Any, ConnectionInformation.DETECTION_PORT);
    var bytes = client.EndReceive(ar, ref endPoint);

    Debug.WriteLine($"Detection request from: {endPoint}");
}
like image 29
plori Avatar answered Sep 16 '22 17:09

plori