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

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).

Related

How to connect windows and android device over internet programmatically on Non-Local network

I want to connect android with windows so that i can send my custom data.
so far i have only seen localhost examples.
but i want to connect my android which is on Sim-internet with windows connected through Ethernet.
this is android's code so far(client)
socket = Socket(address, port)
outputStream = socket.getOutputStream()
outputStream.write(data)
and this is C# windows(server)
IPHostEntry ipHostInfo = await Dns.GetHostEntryAsync("localhost");//localServer
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint ipEndPoint = new(ipAddress, 10090);
Console.WriteLine("initiating " + ipEndPoint.Port + ", " + ipAddress.ToString());
using Socket listener = new(ipEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(ipEndPoint);
listener.Listen(100);
var handler = await listener.AcceptAsync();
while (true)
{
// Receive message.
var buffer = new byte[1_024];
var received = await handler.ReceiveAsync(buffer, SocketFlags.None);
var response = Encoding.UTF8.GetString(buffer, 0, received);
var eom = "<|EOM|>";
if (response.IndexOf(eom) > -1 /* is end of message */)
{
Console.WriteLine(
$"Socket server received message: \"{response.Replace(eom, "")}\"");
break;
}
}
as you can see it is localhost which can only be accessed by localNetworked devices
but i want to connect it over internet from different networked devices
How can i implement that .?
Your socket should bind to all addresses, not the local (new IPEndPoint(IPAddress.Any, ...)).
Your server is most likely behind a firewall/NAT so you need to setup port forwarding so your server can be accessed from the internet.
If the servers public IP address is static then you can use that. Otherwise you have to purchase a domain and configure a DNS server or use a free dynamic DNS service like No-IP or FreeDNS...

Hole Punshing __ Sending to local loop works but sending to external ip not

I spend hours trying to implement Hole punching in C# , my project need a connection to be made directly between me ( server ) and other slaves (peers) , I have third party server that I'm using to keep track external IPs which belongs to the server and peers .
the Code I managed to write until now works fine when I supply an internal IP for the server ( loopback or (0.0.0.0)) but it don't when I put my external ip .. it give no exceptions , but when using a tool like packet sender to test it , the server recieve the datagram just from the loopback , not my external .
here my Server implementation :
class Program
{
static byte[] dataToSend = Encoding.ASCII.GetBytes("Test");
// get the ip and port number where the client will be listening on
static IPEndPoint GetClientInfo()
{
// wait for client to send data
using (UdpClient listener = new UdpClient(11000))
{
IPEndPoint groupEP = new IPEndPoint(IPAddress.Parse("188.247.78.18") , 11000);
byte[] receive_byte_array = listener.Receive(ref groupEP);
return groupEP;
}
}
static void Main(string[] args)
{
var info = GetClientInfo(); // get client info
/* NOW THAT WE HAVE THE INFO FROM THE CLIENT WE ARE GONG TO SEND
DATA TO IT FROM SCRATCH!. NOTE THE CLIENT IS BEHIND A NAT AND
WE WILL STILL BE ABLE TO SEND PACKAGES TO IT
*/
// create a new client. this client will be created on a
// different computer when I do readl udp punch holing
UdpClient newClient = ConstructUdpClient(info);
Console.WriteLine(info.Address.ToString());
// send data
newClient.Send(dataToSend, dataToSend.Length);
Console.ReadKey();
}
// Construct a socket with the info received from the client
static UdpClient ConstructUdpClient(IPEndPoint clientInfo)
{
var ip = clientInfo.Address.ToString();
var port = clientInfo.Port;
// this is the part I was missing!!!!
// the local end point must match. this should be the ip this computer is listening on
// and also the port
UdpClient client = new UdpClient(new IPEndPoint(IPAddress.Any, 11000));
// lastly we are missing to set the end points. (ip and port client is listening on)
// the connect method sets the remote endpoints
client.Connect(ip, port);
return client;
}
}
and this is my Client implementation :
class Program
{
static void Main(string[] args)
{
string ipOfServer = "188.247.78.18"; //this is my external Ip and it doesn't work giving me nothing in the server Console ( but if I replaced it with 127.0.0.1 server console response)
int portServerIsListeningOn = 11000;
// send data to server
Socket sending_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPAddress send_to_address = IPAddress.Parse(ipOfServer);
IPEndPoint sending_end_point = new IPEndPoint(send_to_address, portServerIsListeningOn);
sending_socket.SendTo(Encoding.ASCII.GetBytes("Test"), sending_end_point);
// get info
var port = sending_socket.LocalEndPoint.ToString().Split(':')[1];
// now wait for server to send data back
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, int.Parse(port));
byte[] buffer = new byte[1024];
sending_socket.Receive(buffer); // <----- we can receive data now!!!!!
}
}
how to make this works , and how to test it to make sure that the server working in my pc from outside ?

Sending broadcast packet issue

I am currently working on a C#/Android client/server project.
I have a server application, running C# on Windows, which sends a broadcast message on port 8000.
The idea is the client application (Android) receives the broadcast and then shows the server hostname and IP, from the message sent via the broadcast, on the Android device for the user to select.
Below is how I am attempting to do the broadcast.
int availableTCPSocket = 0;
try
{
//UdpClient udp = new UdpClient();
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
availableTCPSocket = getAvailableTCPSocket();
//IPEndPoint endpoint = new IPEndPoint(IPAddress.Broadcast, BROADCAST_PORT);
IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse("192.168.1.255"), BROADCAST_PORT);
XmlGenerator xmlGenerator = new XmlGenerator();
xmlGenerator.addStartElement("ServerInformation");
xmlGenerator.addElementString("Hostname", Dns.GetHostName());
NetworkAdapterDetails networkAdapterDetails = getNetworkAdapterDetails();
xmlGenerator.addElementString("IP_Address", networkAdapterDetails.ipAddress);
xmlGenerator.addElementString("MAC_Address", networkAdapterDetails.macAddress);
xmlGenerator.addElementString("AvailableTCPSocket", availableTCPSocket.ToString());
xmlGenerator.addEndElement();
xmlGenerator.flushAndCloseXmlWriter();
string udpData = xmlGenerator.returnXml();
byte[] sendBytes = Encoding.ASCII.GetBytes(udpData);
while (true)
{
//udp.Send(sendBytes, sendBytes.Length, endpoint);
socket.SendTo(sendBytes, endpoint);
Console.WriteLine("Broadcast Sent");
System.Threading.Thread.Sleep(5000);
}
}
catch (Exception ex)
{
Console.WriteLine("Broadcast Sender Exception: {0}", ex.Message);
}
If I set the endpoint to be IPAddress.Broadcast it says it is 255.255.255.255 but my devices never receive the broadcast.
If I change the endpoint to be hardcoded to 192.168.1.255 then my devices receive the broadcast.
So because of this I have two questions.
If I use IPAddress.Broadcast why don't my devices receive anything if this is supposed to be broadcast.
If 192.168.1.255 is the correct broadcast address, how can I find out what the addresss should be dynamically, the idea is the server will be provided for download so has to work on different network configurations where 192.168.1.255 might not be the correct address.
It also takes a long time for the device to receive the packet, the server writes to the console each time its looped round and sends the broadcast but it takes about 4 or 5 broadcasts to be sent before the devices receives it. Its on a WIFI network but strong signal on all devices, 60mb download on the internet and 2ms ping between router and devices.
Thanks for any help you can provide.
Windows 7 handles 255.255.255.255 broadcast in a different way. More info here: Send UDP broadcast on Windows 7
use subnet broadcast instead of 255.255.255.255
Code to Get subnet broadcast address
public static IPAddress GetBroadcastAddress(this IPAddress address, IPAddress subnetMask)
{
byte[] ipAdressBytes = address.GetAddressBytes();
byte[] subnetMaskBytes = subnetMask.GetAddressBytes();
if (ipAdressBytes.Length != subnetMaskBytes.Length)
throw new ArgumentException("Lengths of IP address and subnet mask do not match.");
byte[] broadcastAddress = new byte[ipAdressBytes.Length];
for (int i = 0; i < broadcastAddress.Length; i++)
{
broadcastAddress[i] = (byte)(ipAdressBytes[i] | (subnetMaskBytes[i] ^ 255));
}
return new IPAddress(broadcastAddress);
}
You need to enable sending broadcast messages on the socket with socket.EnableBroadcast = true. Then you should be able to send them to 255.255.255.255 just fine.
Reference: http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.enablebroadcast(v=vs.110).aspx
Over wi-fi sometimes doesn't allow the packets send over 255.255.255.255 depending on the security settings in it. Find the broadcast address of the network at run time & use it. You can get the broadcast network address of any network by performing the below operation.
broadcastaddress = (ipaddressofthesystem & netmask) & ~netmask;
Also as an alternative you should consider using multicast address.

Socket c# chat over internet?

I am having trouble with sockets connecting from an external source
See below my constructor.
//Using UDP sockets
clientSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram, ProtocolType.Udp);
EndPoint ourEP = new IPEndPoint(IPAddress.Any, 1450);
//Listen asynchronously on port 1450 for coming messages (Invite, Bye, etc).
clientSocket.Bind(ourEP);
//Receive data from any IP.
EndPoint remoteEP = (EndPoint)(new IPEndPoint(IPAddress.Any, 0));
byteData = new byte[1024];
//Receive data asynchornously.
clientSocket.BeginReceiveFrom(byteData,
0, byteData.Length,
SocketFlags.None,
ref remoteEP,
new AsyncCallback(OnReceive),
null);
this is connect button function:
private void btnCall_Click(object sender, EventArgs e)
{
//Get the IP we want to connect.
otherPartyIP = new IPEndPoint(IPAddress.Parse(txtCallToIP.Text), 1450);
otherPartyEP = (EndPoint)otherPartyIP;
}
I make chat application peer to peer over internet. i opened port 1450 firewall and add port forward but it's not connecting. Please can you help?
When working with UDP you must ensure that the amount of HOPS a packet can travel is set correctly.
I'm not all to sure but I think the default is either 0 or 1.
Use the Ttl property on your socket to experiment with this. Try setting it to 10, if you are testing on a very short path.
Alternatively set it higher byt take care as the ttl property for datagrams denote the amount of points/routers (actually hops) the packet can travel trhough to reach its destination.
The value range can be from 0 to 255.
Hope this helps

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