For some reason the C# socket.RemoteEndPoint started returning the address of the default gateway. It used to work and I know the code hasn't changed. I'm not sure when it started occurring as the logs don't go back far enough so I'm not sure what could have happened to this server to cause this. Everything seems to be working normally. Just not getting the remote IP anymore.
Anyone have any idea what could cause this?
Here is the relevant code.
public void startClientListening(string ipString, int port)
{
IPAddress ip = IPAddress.Parse(ipString);
// Create the listening socket...
clientListenerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipLocal = new IPEndPoint(ip, port);
// Bind to local IP Address...
clientListenerSocket.Bind(ipLocal);
// Start listening...
clientListenerSocket.Listen(32);
// Create the call back for any client connections...
clientListenerSocket.BeginAccept(onClientConnect, clientListenerSocket);
}
private void onClientConnect(IAsyncResult asyn)
{
Socket workerSocket = clientListenerSocket.EndAccept(asyn);
workerSocket.NoDelay = true;
//This returns 192.168.1.1 rather than the remoteIp
string remoteIp = ((IPEndPoint)workerSocket.RemoteEndPoint).Address.ToString();
}
This could happen if the default gateway was a router/ip firewall before but now it is a proxy/application firewall.
In this case the ip connection is instantiated by the proxy and therefore you see the ip address of the proxy and not of the real client.
Related
I'm trying to implement Hole punching using C# but unfortunately I spent hours to figure out why it doesn't work for me. Here is my problem:
I have a third part server that I can manage all external IPs for the peers on, and of course my router is behind a NAT, and I assume all my peers are also behind NATs.
Say if I managed to figure out all slaves (peers), End points (external ips). Where to put the external ip address of my server which runs on my pc (not the third party one), and where to put the peer ip address?
This is my code:
public void HolePunch(String ServerIp, Int32 Port) // if I put my external ip here I get Exception (An address incompatible with the requested protocol was used)
{
IPEndPoint LocalPt = new IPEndPoint(Dns.GetHostEntry(Dns.GetHostName()).AddressList[0], Port);
UdpClient Client = new UdpClient();
Client.ExclusiveAddressUse = false;
Client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
Client.Client.Bind(LocalPt);
IPEndPoint RemotePt = new IPEndPoint(IPAddress.Parse(ServerIp), Port);
// This Part Sends your local endpoint to the server so if the two peers are on the same nat they can bypass it, you can omit this if you wish to just use the remote endpoint.
byte[] IPBuffer = System.Text.Encoding.UTF8.GetBytes(Dns.GetHostEntry(Dns.GetHostName()).AddressList[0].ToString());
byte[] LengthBuffer = BitConverter.GetBytes(IPBuffer.Length);
byte[] PortBuffer = BitConverter.GetBytes(Port);
byte[] Buffer = new byte[IPBuffer.Length + LengthBuffer.Length + PortBuffer.Length];
LengthBuffer.CopyTo(Buffer,0);
IPBuffer.CopyTo(Buffer, LengthBuffer.Length);
PortBuffer.CopyTo(Buffer, IPBuffer.Length + LengthBuffer.Length);
Client.BeginSend(Buffer, Buffer.Length, RemotePt, new AsyncCallback(SendCallback), Client);
// Wait to receve something
BeginReceive(Client, Port);
// you may want to use a auto or manual ResetEvent here and have the server send back a confirmation, the server should have now stored your local (you sent it) and remote endpoint.
// you now need to work out who you need to connect to then ask the server for there remote and local end point then need to try to connect to the local first then the remote.
// if the server knows who you need to connect to you could just have it send you the endpoints as the confirmation.
// you may also need to keep this open with a keepalive packet untill it is time to connect to the peer or peers.
// once you have the endpoints of the peer you can close this connection unless you need to keep asking the server for other endpoints
Client.Close();
}
public void ConnectToPeer(String PeerIp, Int32 Port)
{
IPEndPoint LocalPt = new IPEndPoint(Dns.GetHostEntry(Dns.GetHostName()).AddressList[0], Port);
UdpClient Client = new UdpClient();
Client.ExclusiveAddressUse = false;
Client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
Client.Client.Bind(LocalPt);
IPEndPoint RemotePt = new IPEndPoint(IPAddress.Parse(PeerIp), Port);
Client.Connect(RemotePt);
//you may want to keep the peer client connections in a list.
BeginReceive(Client, Port);
}
public void SendCallback(IAsyncResult ar)
{
UdpClient Client = (UdpClient)ar.AsyncState;
Client.EndSend(ar);
}
public void BeginReceive(UdpClient Client, Int32 Port)
{
IPEndPoint ListenPt = new IPEndPoint(IPAddress.Any, Port);
Object[] State = new Object[] { Client, ListenPt };
Client.BeginReceive(new AsyncCallback(ReceiveCallback), State);
}
public void ReceiveCallback(IAsyncResult ar)
{
UdpClient Client = (UdpClient)((Object[])ar.AsyncState)[0];
IPEndPoint ListenPt = (IPEndPoint)((Object[])ar.AsyncState)[0];
Byte[] receiveBytes = Client.EndReceive(ar, ref ListenPt);
}
EDIT :
the code works will if I give it my local ip and if my clients in my pc .. but if I supply it an external ip it doesn't work ( the exception in the first line comment )
I have a program shown below:
Socket receiveSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram, ProtocolType.Udp);
EndPoint bindEndPoint = new IPEndPoint(IPAddress.Any, 3838);
byte[] recBuffer = new byte[256];
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
receiveSocket.Bind(bindEndPoint);
receiveSocket.Receive(recBuffer);
}
and it is working but when I want to just listen to a specific IP address it does not work,
it throws an exeption "the requested address is not valid in context"
new code:
EndPoint bindEndPoint = new IPEndPoint(IPAddress.Parse("192.168.40.1"), 3838);
The IP addresses you are binding to, should be one of the IP addresses that are actually assigned to the network interfaces on your computer.
Let's say you have an ethernet interface and a wireless interface
ethernet: 192.168.1.40
wireless: 192.168.1.42
When calling the Bind method on your socket, you are telling it on which interface
you want to listen for data. That being either 'any of them' or just the ethernet interface for example.
I'm guessing this is not what you are looking for?
Perhaps you are trying to restrict who can make a connection to your server
So whate you may be looking for is
var remoteEndPoint = new IPEndPoint(IPAddress.Parse("192.168.1.40"), 0)
receiveSocket.ReceiveFrom(buffer, remoteEndpoint);
This restricts the source from which you accept data.
I'm going to setup a small client/server server in TCP/IP mode, I use VS2010,C# to develop my apps, I've googled a lot and could find some source codes, but none of them work in internet, I can get some answers in my own local system, i.e. I run my server, then listen for my own localhost (127.0.0.1) then send some data (for example using telnet), it works fine but when I do the same over internet I get nothing! I want to use port 80, as I want to send/receive http data, I have tested several source codes, here is the last code I have used (and it works on localhost with telnet)
//server code:
form_load()
IPAddress localAddress = IPAddress.Parse("127.0.0.1");
Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipEndpoint = new IPEndPoint(localAddress, 80);
// Bind the socket to the end point
listenSocket.Bind(ipEndpoint);
// Start listening, only allow 1 connection to queue at the same time
listenSocket.Listen(1);
listenSocket.BeginAccept(new AsyncCallback(ReceiveCallback), listenSocket);
Console.WriteLine("Server is waiting on socket {0}", listenSocket.LocalEndPoint);
// Start being important while the world rotates
while (true)
{
Console.WriteLine("Busy Waiting....");
Thread.Sleep(2000);
}
public static void ReceiveCallback(IAsyncResult AsyncCall)
{
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
Byte[] message = encoding.GetBytes("I am a little busy, come back later!");
Socket listener = (Socket)AsyncCall.AsyncState;
Socket client = listener.EndAccept(AsyncCall);
Console.WriteLine("Received Connection from {0}", client.RemoteEndPoint);
client.Send(message);
Console.WriteLine("Ending the connection");
client.Close();
listener.BeginAccept(new AsyncCallback(ReceiveCallback), listener);
}
send data (client), of course I haven't used this code, is it right?
public static string SendData()
{
TcpClient client = new TcpClient();
client.Connect(IP, 80);
StreamWriter sw = new StreamWriter(client.GetStream());
StreamReader sr = new StreamReader(client.GetStream());
//if statement evalutes to see if the user has selected to update the server
//" " = update server
//"" = do not update the server
//if (updateData.Equals(""))
//{
// space = "";
//}
//else if (!updateData.Equals(""))
//{
// space = " ";
//}
//Refrences stream writer, username variable passed in from GUI
//space variable provides update function: "" = dont update. " " = update database.
sw.WriteLine("h");
sw.Flush();
//data send back from the server assigned to string variable
//string recieved = sr.ReadLine();
return "";
}
I'm going to have the server code in my Server (winserver 2008R2) but currently test it in normal PCs, what am I doing wrong? I want to send some http packet from a random system (with a random IP) to my server (which I know its IP), what should I do? is it possible with tcp/ip or I should do something else?
is it related to static IP? should I certainly have static IP? my web server has a static IP but my clients do not, is it a problem?
I think I have some problem in defining ports and IPs, how should I set them? my server has a specific IP, but I don't know IP of my clients, would you please explain it to me step by step?
thanks
The two most common problems in this scenario:
Ensure your server's router is using port forwarding to forward HTTP requests from the router to the server.
Ensure you are connecting to the server's public IP address, not its local network address.
While testing my Client-Server program, I encountered a weird exception when trying to connect to the server on a different router:
"A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond."
The client can connect to the server perfectly in the local network, however it doesn't work when it is over the internet.
I port forwarded port 1250 (the one I'm using), and using SimplePortForwarding (http://www.simpleportforwarding.com/) I verified that the port was open and working.
I based my implementation on this tutorial:
http://www.developerfusion.com/article/3918/socket-programming-in-c-part-1/
Any idea what is wrong?
Thanks!
Here is the server listen method:
public void startListening(int port)
{
lock(_locker)
{
_listeningSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
// Bind socket to local endpoint, and listen for incoming connections
IPEndPoint ipEndpoint = new IPEndPoint(IPAddress.Any, port);
_listeningSocket.Bind(ipEndpoint);
_listeningSocket.Listen(10);
waitForNewClient();
// successfully started listening
_isListening = true;
} catch (SocketException e)
{
// failed for some strange reason
_isListening = false;
}
}
}
Here is the client connect code:
public String connect(String ipAddress, int port)
{
lock(_locker)
{
if (!_connecting)
{
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse(ipAddress), port);
try
{
_socket.Connect(endpoint);
_connected = true;
waitForData();
_eventManager.queueEvent(new PlayerJoinedEvent(PlayerJoinedEvent.PLAYER_JOINED, name));
} catch (SocketException e)
{
// Exception is thrown HERE
return e.Message;
}
}
}
return "";
}
Make it sure that your Server IP address is public unless it is not reachable.
Check this link for private address spaces.
You opened port 1250 on the server or the client router? It needs to be opened on the server router. You may need to make sure your server is connected to your DMZ port and/or have DMZ enabled on your server router.
Hope this helps.
I Fixed the problem.
The IP Address I used was the internal ip address I got from ipconfig, but the IP address I needed to use was the external one, the one you get from services like http://www.whatsmyip.org/.
I'm still confused as to why these two numbers are different.
The prog in c#:
private void listBox1_Click(object sender, EventArgs e)
{
String data = (String)this.listBox1.SelectedItem;
data = data.TrimEnd(new char[] { '\r', '\n' });
try
{
ip = Dns.GetHostAddresses(data);
}
catch (SocketException ex)
{
MessageBox.Show(ex.ErrorCode.ToString());
}
clientIP = new IPEndPoint(ip[0], 6000);
newSock.Bind(clientIP);
newSock.Listen(100);
resetEvent.Set();
}
In the above code, I obtain the ip-address of the remote host who is shown in the listbox and correspondingly in order to start accepting messages need to create an IPEndPoint(clientIP).
newSock is a variable of type socket initialized as:
newSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
The problem is in the line where I bind the socket newSock to the IPEndPoint clientIP where I am getting an error saying it is an invalid address.
However to cross check I tried to display the ip-address on a message box which it did correctly.
So what exactly is going wrong??
You shouldn't bind a socket to remote host address. It's used to indicate on which inbound IP address you should listen. You should either specify one of your own IP addresses (if you want to listen only on a single IP) or specify IPAddress.Any (0.0.0.0) to listen on all IP addresses you have.
By the way, if you want to connect to a remote address, you shouldn't use Bind at all. You'd just use the Connect method