i've written a simple local messenger with c# for use of myself. now it works over a local network(lan,wifi) and works fine.
now i want to give it to my friend and use it over internet but have no idea how to use different ip except local host.
i'd be grateful for any help.
thanks in advance.
private void InitializeConnection()
{
ipAddr = IPAddress.Parse(txtIp.Text);
tcpServer = new TcpClient();
tcpServer.Connect(ipAddr, 1986);
Connected = true;
UserName = txtUser.Text;
txtIp.Enabled = false;
txtUser.Enabled = false;
txtMessage.Enabled = true;
btnSend.Enabled = true;
btnConnect.Text = "Disconnect";
swSender = new StreamWriter(tcpServer.GetStream());
swSender.WriteLine(txtUser.Text);
swSender.Flush();
thrMessaging = new Thread(new ThreadStart(ReceiveMessages));
thrMessaging.Start();
}
this the client part
public ChatServer(IPAddress address)
{
ipAddress = address;
}
private Thread thrListener;
private TcpListener tlsClient;
bool ServRunning = false;
public static void AddUser(TcpClient tcpUser, string strUsername)
{
ChatServer.htUsers.Add(strUsername, tcpUser);
ChatServer.htConnections.Add(tcpUser, strUsername);
SendAdminMessage(htConnections[tcpUser] + " has joined us");
}
and this server part.
Intro
To be able to get another user to connect to a computer of yours, there are a quite a few things you are going to have to do. Hopefully, this should work but networking can get complex in general and not all networks run alike. I assume you are running this behind some sort of router that you have access to. Networking is complex and that really is why this answer is so awfully long (if you are questioning yourself on reading the rest of it). For the most part it is pretty straight and forward, but might take some time.
And before you get started, just a:
Forewarning
Thinking security wise, like almost everything on computers and with networking in general, there is not really something called "entirely safe" (at least as far as I know). As with networking, opening ports is not entirely safe. I'm not a top notch security expert, but by doing this, you are allowing other computers to send and receive data with your computer. This should be safe in your case of just having a simple text chat, but in other cases this might not be the same. With more complex and important cases such as dealing with SSH and FTP, there is more security involved. Just as a warning, make sure to take care when messing with your network, or with computers in general.
Getting Started
Anyways, (if I have not scared you off yet) these are the steps that I had to take to get something like your chat server working:
Forwarding the port on your router
The first thing you are going to have to do is forward or open the port on your router. Well, before you can even do this, there are several things you need to understand about networking:
Basically, your router is what connects your network of computers to the internet and allows connections to be be made through ports. If you don't understand what a port is, it is what is used for internet connections to be made and basically acts like the house number to a street address. It tells where on that street the house it and is more specific than just the street address. In terms of networking, this is a number which tells the specific place the communication is going. The port number ("the house number") is telling where on the computer's IP address ("the street address") to connect.
Specifically, the port number is an 16-bit unsigned integer ranging from 0 to 65535 (but port number 0 actually cannot be used according to Wikipedia) Even though this is a 16-bit unsigned integer which would be a ushort or a UInt16 in C#, when using a TcpClient or a TcpListener, they instead use a signed 32-bit integer instead which is the standard int or a Int32. Also, The port is generally denoted after an IP address with a colon (":"), for example 123.45.67.89:80 but might be different in other cases. This is using IPv4 but there is also IPv6 which I have not yet worked with.
Now, what about forwarding the port and why do you need to do that? What forwarding the port does is forward connections to a certain port on the router to a computer which is behind the router instead. There is not always a simple, straight and forward way to do this since router companies have different ways of accomplishing this. Generally, to figure this out, you can Google for instructions on how to forward the port on your particular router, so for example you can search for "forward port on router company's name router" to find it. To do this, you are probably also going to need a few things before getting started with that:
You are going to need your routers admin user name and password which is generally not (and probably should not be) what is used to connect to it with. If you don't know what it is, whoever setup your router should know. Once you have got this working you are ready to move on.
You are also probably going to need the your computer's local IP address which is used to address the computers in the router's network. To find this, your router will probably tell you what it is, but here are the steps to do it on Windows if you can't seem to find it.
Open up command prompt
Open the run dialog by going to Start >> Run... or by pressing Win+R
Type cmd and press enter
Run ipconfig by typing it in and pressing enter to find your computers IP address
You should see a list of network interface connections
To find the one we are looking for, you want to find the network connection you are using to connect to the internet through your router. It is probably different on computer but in my case its named Wireless LAN adapter Wireless Network Connection since I'm using a laptop. The name, I would assume, probably has LAN in it.
This should not have: Media State . . . . . . . . . . . : Media disconnected listed under it since you need to be connected to your router. If you are not then simply do so.
Instead, there should be IPv4 Address. . . . . . . . . . . : with the IP address of your actual computer listed next to it. This is the IP address of the computer whose port you want to forward. Of course, this might be different if you are using a router using IPv6.
Also, in the process of doing this, your port number that were using may be taken by another process or service. This is okay and easy to fix; you just have to change the port number. You are going to want to trying a high number such as 8500 for example until you find one that works. Once you have that number, just update the port number in your code. To make this even easier it, is much easier to have a constant that stores this such as:
const int Port = 8500;
So then you can have the client connect with:
tcpClient.Connect(ipAddress, Port)
And then have the server listen with
TcpListener tcpListener = new TcpListener(ipAddress, Port);
As with other global variables such as the port number that you might have, it may be better to create a global variable class, but at the same time, that may also introduce other issues by using it such as with global properties with threading. Just a suggestion and a heads up.
Though, once you have managed to complete forwarding the port, you can move on to the much simpler part of getting your friend to actually connect to your server.
Geting your router's IP address
Once you have managed to do all of that, you probably should give your a pat on the back because that is the real actual part of getting your router to cooperate with what you were trying to do. Now you just have you give your IP address, port number, and of course your client program to your friend, so he or she can connect to the server. To get your router's public IP address you can go over to the ironically called website at http://www.whatismyip.com/. Here you can get your public IP address but also make sure that it says "No Proxy Detected" below it. If you are using a proxy, hopefully you know what that is and can connect to the internet without to get your IP address. (Trust me, you don't want me to explain want a proxy is for now)
Now once you have got that, you are going to want to send that IP and also your port number to your friend. To be smart about it, you don't want this publicly displayed as you probably don't want a bunch of random people trying to break into your network. Sending it over IM or email should (hopefully) be fine as long as your friend does not publicly display it. So when sending your IP address, just be smart about it.
Once you have done that, just don't forget to actually start your server! Without your server running, there is no way to communicate to the clients and accept incoming connections. This will save a lot of frustration from accidentally forgetting to.
Conclusion
Hopefully, this will help you be able to create a cool chat program and also understand a few other things in the process. I really wish this was not so long, but networking is really just complicated in for the most part.
Hope this helps you quite a bit!
Related
I am trying to convert a VBScript COM component based Reverse/Forward IP checking system to C#.
This system was created to prevent the banning of SERPs like Googlebot using what was back then (becoming) the standard way of checking an IP was who it said it belonged to e.g a reverse/forward DNS check.
Although we have lists of SERP IP Ranges so we don't ban them if they come in - even with hack vectors - we cannot keep up with new ranges being added all the time.
The process is based around this short example.
It is explained simply here > http://ipadmin.junkemailfilter.com/rdns.php
This has been working fine for ages in VBScript but now I am converting to .NET I am having issues where people have set their IP to resolve to "localhost" like this one 113.168.154.182 as you just get back your own DNS server, Virgin media, or if I run it from my PC with c# I get my own computer name. The IP is from Vietnam > http://www.geoiptool.com/en/?ip=113.168.154.182
Now I am trying to use .NET and this code.
But as I am using this code to do get the hostname
IPHostEntry DNSHostIP = Dns.GetHostEntry("113.168.154.182");
hostname = DNSHostIP.HostName;
When I output the value of hostname I get my own computers name e.g std36w7.metal.mycompany.co.uk not localhost.
Then when I try and do a forward DNS check to get the list of IP addresses with this hostname I get my own IP addresses (one IPv6 one IPv4).
If I could get back "localhost" then I could have a check to skip it as a spoof along with anything starting with 10 or 192 etc.
However at the moment I cannot do this.
What is the best way of doing reverse/forward DNS checks which I thought was becoming the standard way of checking for spoofers nowadays in .NET?
And how can I handle people who have set (or some mistake might be causing it) their IP to be localhost.
Thanks
Simple. Your LOCAL DNS (guessing your router unless you have your own DNS server) is resolving it - upstream to it's INTERNET DNS server. Also if you really want it to return LOCALHOST, you'd have to literally edit your local HOSTS file and add an entry since no system ever returns the name LOCALHOST when you look up your ip even from a local DNS server. I believe the ONLY example is if you completely eliminate a DNS server to fallback on your local HOSTS file.
I have two computers and they are connected via ethernet, i have set up an WCF connection and this all works ok, however when i host the same wcf on the local pc as the one i want to comunicate to and then do a wcf request via a channel, the request does not go to the remote pc but to my local pc. Is there a way to force a wcf request from a channel to go trough a specific ipaddress and not just go to any?
i'll try to explain how i use this:
there are two computers they are both similar and have two network adapters who have the same ipaddess and run thesame wcf software. so for example ipaddress for adapter 1 is: 10.10.10.1 and the other adapter is 10.10.10.2 on the same pc, and the other pc is similar. now these two pc need to communicate so i wire the two network adapters in cross example: pc 1 network adapter one goes to pc 2 network adapter 2. this so they are connected in 2 ways. so if i want to communicate with a simple socket from one to the other and back over the second adapter this all goes ok becouse i can bind a socket to a ipaddress and it will send it via the adapter it is bound to. but this does not seem to work with WCF. if i have two hosts on one pc, one for adapter 10.10.10.1 and one on 10.10.10.2 for the other adapter and i send a message to 10.10.10.2 that is on the remote pc, it will go in via the second network adapeter.
PC1 network adapter 1 (10.10.10.1) <--direct patch cable connection--> PC2 network adapter 2 (10.10.10.2)
PC1 network adapter 2 (10.10.10.2) <--direct patch cable connection--> PC2 network adapter 1 (10.10.10.1)
These connection arrows are direct connection patch cables!
all network adapters have a wcf hosted, and the software on both pc's is thesame.
this is all done for redundancy, more then two pc can be connected in a chain with this.
this is a little example of how i setup a request to the remote host:
public void Test()
{
string endPoint = "net.tcp://10.10.10.2:9985/connection";
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None);
binding.ListenBacklog = 2000;
binding.MaxConnections = 2000;
binding.TransferMode = TransferMode.Buffered;
binding.MaxReceivedMessageSize = 104857600;
binding.SendTimeout = new TimeSpan(0, 1, 0);
binding.CloseTimeout = new TimeSpan(0, 0, 1);
binding.OpenTimeout = new TimeSpan(0, 0, 1);
binding.ReceiveTimeout = new TimeSpan(0, 1, 0);
//binding.HostNameComparisonMode = HostNameComparisonMode.Exact;
//binding.PortSharingEnabled = false;
ChannelFactory<Connection> pipeFactory = new ChannelFactory<Connection>(binding, new EndpointAddress(endPoint));
var pipeProxy = this.ChannelFactory.CreateChannel();
//fictional method: pipeProxy.SendRequestTunnelTo("10.10.10.1"); //this is the ipaddress that it should go out to however it goes out to "10.10.10.2"
//and this is another network adapter also on the local mashine and here is also a wcf host on
((IClientChannel)pipeProxy).AllowOutputBatching = true;
((IClientChannel)pipeProxy).Open();
pipeProxy.SystemRequest(); //do function
}
Ok, the issue here is routing. If windows thinks it can deliver the traffic directly to the other IP Address, it will do so.
In this case, it can't differentiate between the local 10.10.10.2 that it knows about and one that's on another network hidden behind a NAT.
The preferred solution is to not use the same subnet (so have 10.10.10.2 and 10.11.10.2 or similar), however that can sometimes require significant changes.
The next best option is to use the IP address of the NAT and have it port forward.
Say you have a setup like this (where the boxes with 2 ip addresses are NATing routers with both public and internal IPs)...
10.10.10.2 --- [10.10.10.1 | 1.2.3.4] --- Internet --- [5.6.7.8 | 10.10.10.1] -- 10.10.10.2
Then the machine on the left should try to connect to 5.6.7.8 which should forward connections to the machine on the right (and vice-versa with the right machine connecting to 1.2.3.4).
If you've got a WAN setup that makes the machines appear to be in the same network, that's as much of a problem as being on the same network. None of the routers on the network will be able to determine which 10.10.10.2 you mean,
If you weren't using exactly the same IP address, you might be able to force the issue using routing tables on your windows box. This can allow you to specify preferential routes so that all traffic for a given IP address goes out over the specified NIC. Unfortunately, beyond that point it's out of your control and entirely up to the network hardware how the packets are routed. If you have the ability to configure routing on the intermediate hardware, you could fix the route the whole way to the destination but this is usually an awful lot of work and likely to be broken when kit is updated/replaced as it's non-standard.
If you decide to look into forcing routes, start with the Windows route command
Edit: Re: Forcing routing over an interface...
the syntax is route add target mask gateway costmetric interfaceid
run route print at a command prompt and make a note of the interface id you want to use form the top of the output
then add a route like this:
route add 10.10.10.2 255.255.255.255 10.10.10.2 1 [interface id from above]
on my machine that would be
route add 10.10.10.2 255.255.255.255 10.10.10.2 1 11
Note that in this case we're telling it to use 10.0.0.2 as a gateway. I have no idea what the consequences of doing this will be as software attempting to access itself via a locally bound port might get very confused. Last caveat: I don't have a pair of physical machines to hand that I can test this on, and VMs don't really count as their networking is slightly different.
We're providing a cost metric of 1. This should give it a very high priority meaning it should be chosen above all other routes to that IP address.
The route will be lost when the system reboots. You can use a -p flag after route add to make the route persistent. I suggest you don't do this until you're sure it's working as intended.
2nd Edit: I think you're heading down a rabbit hole here. While it may be possible to trick the system into working this way, it's definitely not a common usage and I haven't been able to find anything that says it's supported.
It seems like your fundamental problem is that you've got no way to negotiate before assigning IP addresses as you have no network connectivity.
Some thoughts...
Sharing the IP is not going to be robust, so decouple from it. Instead of using a fixed IP in the url, determine the other IP address programatically.
You could have two builds, one which uses .1/.2 and the other which uses .3/.4. Any build1 could then talk to any build2 but not 1-1 or 2-2. This is a bit awkward but would work with little effort on your part.
Better would be to assign unique IPs to every machine you build, then provide a way to detect the other machine's address. Service location protocol is a likely candidate for this approach. Once you know the IP address you need to communicate with, configuring WCF should be trivial.
If assigning unique IPs is problematic, you could potentially have DHCP servers on all nodes but only turn them on if another one doesn't exist on that network (pair). That way, every machine would end up with valid IP addresses with no prior configuration.
Your endpoint address needs to identify the IP address you are targetting.
I'd like the user to be able to enter the MAC of a computer on the network. Once they've done that, it'll add it to a list. The program will then ping all of those MACs on the list every time the class is called (I know this isn't necessarily possible, but read on).
Normally I'd simply use IP addresses, but they aren't static, and there are a -lot- of devices on the network that I don't care about the connectivity of for this program. If they don't respond, I'd like it to pop up a message box.
NOW, that being said, the only part I'm having trouble with is the actual part where I ping something. I know that an actual "ping" is not possible when it comes to MAC addresses, so how could I check for something like that? Alternatively, if it's easier, I could also accept pinging something based on the computer name.
EDIT: I'd prefer not to have to use things like arp to find the IP addresses of the devices I want. Like I said though, I'm also interested in whether or not it's possible to search for devices by name. Would that work?
If you have a properly administered environment, you should be using names. By properly administered environment, I'm primarily meaning having a DNS server on your local network.
I have something similar running that pings industrial ethernet devices. These are statically assigned addresses, so they don't register themselves with DNS as a DHCP client would. I had our DNS administrator create records for them so I can just use their name. You'll be better off in the long run as two years from now you're going to have NO idea what that mac address in your list was referring to. When creating names, you can make them as descriptive as necessary.
EDIT: Here's a function that takes a name as a string, looks up the associated IP from DNS, then pings. If DNS resolution fails or the ping doesn't report success, the function returns false. It returns true otherwise. You should also log the exceptions for troubleshooting later, BTW.
public bool Check(string Name)
{
//try dns resolution, if fails, quit reporting error
IPAddress[] addresses = null;
try
{
addresses = Dns.GetHostAddresses(Name);
}
catch (SocketException)
{
return false;
}
//ping remote address
PingReply reply = ping.Send(addresses[0]);
switch (reply.Status)
{
case IPStatus.Success:
return true;
break;
default:
return false;
break;
}
}
EDIT 2: Here are the namespaces I'm using in this project. Not sure what's where exactly, but adding these three will get everything going.
using System.Net.NetworkInformation;
using System.Net;
using System.Net.Sockets;
You need to use RARP http://en.wikipedia.org/wiki/Reverse_Address_Resolution_Protocol
and
MAC address to IP Address on Same LAN in C#
Depending on the network, you may be able to use the arp cache to look up the IP of a given MAC address (even if your network is set up such that you could do this, it will only work if the MAC address of the other machine is in the cache at the time of the request). You can read about arp on Wikipedia
If you have the MAC address you can get the IP address and machine name using MAC address. Once you have the IP you can simply ping the machine.
See this code for an example of how to get IP address from MAC address
What is the easiest way to find the next unused IP address on a local adaptors subnet?
IPAddress GetNextFreeIP(NetworkInterface intface)
{
...?
}
Update
I've written a BOOTP/TFTP server that could be used in many different scenarios (cross-over cable, small private network, large corporate network). I have to give the small embedded system I'm updating an IP address and would like to find a spare one for it to use...
If you have DHCP-managed IP ranges, you have an instance you can talk to - the DHCP server (like David recommended)
If you don't have managed IP ranges and no other instance you can talk to, there is no reliable way to tell if an IP is used or unused. IP does not offer such a service itself.
Apart from asking the DHCP-server, I guess you could do a broadcast ping on the subnet and collect the responses from all computers and simply sort the IP-addresses to find the next one. This assumes, of course, that all devices are on-line and responds to broadcasts. So in a pretty controlled environment, this could work.
The short answer is you can't, as Thorsten79 just said.
A slightly longer answer:
It depends on your network's configuration: how the admin has decided to allocate ip addresses. Usually there's a mix of manually assigned ip addresses for servers, routers etc, and a set of dhcp assigned ip addresses for workstations and such.
If you can talk to the dhcp server you might find out which addresses in the reserved range are free, but for the rest of the addresses you cannot find out.
The more interesting question is what you are trying to accomplish? Perhaps it can be realized in a different manner?
From what I've seen of embedded devices with a TFTP server, they boot up with a hard coded IP Address that is documented. After a set period of time (~3-10 seconds), the boot loader transfers control to the application that reads its configuration and sets the IP Address.
If someone wants to use the boot loader to load new firmware, then they need to read the documentation, make sure that IP Address is reachable (on the same subnet), reboot the device, and TFTP the application to the device.
You are all technically right when you say there is no way to ensure an IP isn't being used. But I've decided to rely on this for now...
public static IPAddress FindNextFree(this IPAddress address)
{
IPAddress workingAddress = address;
Ping pingSender = new Ping();
while (true)
{
byte[] localBytes = workingAddress.GetAddressBytes();
localBytes[3]++;
if (localBytes[3] > 254)
localBytes[3] = 1;
workingAddress = new IPAddress(localBytes);
if (workingAddress.Equals(address))
throw new TimeoutException("Could not find free IP address");
PingReply reply = pingSender.Send(workingAddress, 1000);
if (reply.Status != IPStatus.Success)
{
return workingAddress;
}
}
}
I'm following a tutorial # http://www.geekpedia.com/tutorial239_Csharp-Chat-Part-1---Building-the-Chat-Client.html to try and gather the basics of networking. For those not wanting to hit the jump, it's a quick tut demonstrating how to program a simple client-server-model chat application.
When I try and run the code in the tut, it works fine as long as both the client and the server are on the same network, but the second I try and do it externally (getting a mate to run the client app, and running the server app my side), it all goes to pot. The fact that the code works when in the same network leads me to believe that it's not a coding issue, but an issue with the way my network is set up.
I'm trying to run the server on my IP address at port 21719, which I have opened, but still other people can't connect to my server, not able to get any form of response at all.
The code (from the tut) that is being used for the server to listen to connections is:
public void StartListening()
{
IPAddress ipaLocal = ipAddress; //ipAddress is parsed from txtIP
tlsClient = new TcpListener(ipaLocal, 21719);
tlsClient.Start();
ServRunning = true; //for the running loop
// Start the new tread that hosts the listener
thrListener = new Thread(KeepListening);
thrListener.Start();
}
Now, the tutorial does actually point out that
IPAddress ipaLocal = ipAddress;
Will cause issues on some configurations, and I'm beginning to fear that my configuration may be included in that.
So, does anyone have any solution for me?
Thanks,
Sam
What is the local IP address that you're using? (ipAddress) If it's 127.0.0.1, that's not correct (I don't know how it would work internally either, but Windows seems to use magic from time to time). Also, if you have multiple NICs in your local machine, maybe the port forwarding is only set up to forward to one of them, and you're using the IP of the other?
If that's not the problem, here are a few generic suggestions:
Grab a copy of netcat. It's a small network testing util whose only job is to form a simple TCP connection. That will allow you to eliminate your code as a variable in all this. If netcat can form a connection, then you know the problem is your code. If not, you've confirmed that it's your router.
You can use WireShark (or TShark) to look for ICMP packets. Capture ICMP packets on the remote machine. If you get "Destination Unreachable" from the router, you've again proved that it's your router.
As Spencer said you need to make sure Port Forwarding is setup on your router, to forward all packets that come in on port 21719 to your internal machine. As for exactly how to do that, it's hard to say without knowing what type of router.
Are you having people use your external (internet) IP address? (See yours here.)
Have you pinholed your router to forward all communications from port 21719 to your server?
Some tips:
What kind of operating system are you using? Please check the Scope and/or Profiles (under Advanced tab) of your firewall rule.
While your friend is trying to telnet to the port (connect to the im server) monitor the traffic using Wireshark or Network Monitor (Wireshark have problems with Vista and Win 7). If you don't see anything hitting your machine the problem is probably on the router side. Double check the settings - you said you set the forward rule (NAT) but did it also set the rule on firewall of your router?