I need to write a win32 c/c++ application which will be able to determine whether the PC it's running on is connected to one of 2 networks. The first network is the company LAN (which has no internet connection) and the second network is a standalone switch with a single PC connected to it (the PC that the program is running on).
I'm pretty new to network programming but so far I have tried testing to see if a network drive which is held on our LAN can be mapped. This works fine if the PC is connected to the LAN, the drive mapping succeeds so so LAN detection is successful. However, if the PC is connected to the switch, this results in a VERY long timeout which is not a suitable as it will delay the program so much as to make it unusable.
Does anyone have any alternative suggestions?
I'm using c/c++ in VS 6.0
[Update]
Whilst trying a few different ideas and looking at some of the suggestions below I thought I should update with some additional information as many (if not all) of the suggestions I don't think will work.
(1) The aforementioned LAN has no external connections at all, it is completely isolated so no resolving of external DNS or pinging websites is possible.
(2) Hostname, MAC address, IP, Default Gateway, Subnet etc etc (basically everything you see in ipconfig -all) are all manually configured (not dynamic from the router) so checking any of these settings will return the same whether connected to the LAN or the switch.
(3) Due to point (2), any attempts to communicate with the switch seem to be unsuccessful, in fact almost all networking commands (ping, arp etc) seem to fail - I think due to the machine trying to connect to the LAN when it isn't there :-(
One thing I have found which works is pinging the default gateway IP which times out when connected to the switch. This is sort of ok as I can reduce the timeout of ping so it doesn't just hang for ages but it feels like a bit of a hack and I would certainly appreciate any better solutions.
Thanks
As far as TCP/IP is concerned there is no such thing as a LAN on WAN. There are a set of non-internet routable addresses like 192.168.x.x and 10.x.x.x but these are sometimes used by ISP short of IP addresses.
You best bet is to use Asynchronous APIs when making TCP/IP connections. WIN32 defines a whole buch of OVERLAPPED APIs for this purpose. This will prevent your application from grinding to a halt while waiting for a remote connection.
Alternatively put the socket stuff into another thread and then only notify the UI when the operation is done.
I would first try to differentiate between the two using information available locally--that is, from your computer. Does the output of ipconfig /all differ depending on which network you're connected to? If so, exploit that difference if you can.
Is it possible to get the MAC address of the standalone switch? Of the switch that controls the company LAN? That would be a sure way to tell. Unless somebody cloned the MAC address.
If you try using the existence or non-existence of some network service to determine which network you're connected to, you can never be sure. For example, if you failed to map that network drive, all you know is that the network drive isn't available. You can't say for certain that you're not connected to the company LAN. Same is true if you use ping. Lack of response from a particular machine means only that the machine didn't respond.
Various things you can look at for differentiation:
DNS domain name (GetComputerNameEx)
MAC address of gateway (ping it, then GetIpNetTable)
Routing table(do you have a gateway and default route on the company LAN)
WNet discovered network resources (WNetOpenEnum, WNetEnumResource)
Ability to resolve external hostnames (try a 5-10 names like www.google.com, www.microsoft.com and so on, if one resolves you should have internet)
You'll have to decide how many indicators are "enough" to decide you're on one or the other LAN though if tests fail. Then keep retrying until you have a definite result.
http://msdn.microsoft.com/en-us/library/aa366071%28v=VS.85%29.aspx has a lot of network related functions that you can experiment with to create further indicators.
Related
I've just began reading information about multicast transfers using boost::asio and I'm somewhat puzzled by the following:
Why do we need a "listening address" in the following boost::asio example? What's the point of that? Why would one choose anything different than localhost?
http://www.boost.org/doc/libs/1_37_0/doc/html/boost_asio/example/multicast/receiver.cpp
Specifying the listening IP address is necessary when you have more than one network interface card (each NIC is bound to a different IP address).
In your apartment...
When you're working at home on your laptop, you probably don't care. The primary goal is usually to connect anything to everything it wants to within your machine, in which case localhost is just fine.
... but servers do care!
High-end servers, on the other hand, usually have more than one network card. Even better, high-performance network cards often have more than one physical plug, and both of them may be active with different DHCP leases.
Servers will also often be part of public and private networks, which may or may not include a VPN which has its own subnet and accessibility parameters. Sysadmins think about these addresses a lot, and they care deeply about which particular address each service is available. Is it a private service? Is there an untrusted subnet that shouldn't be making these requests?
These questions span both security and system organization concerns. It's not specific to multicast: the UNIX bind system call also takes a specific address for all of the above reasons.
If a program is running on a Linux machine, is there a way for that program to scan for ports that are allowed through the firewall? for example, if a programmer wants to make a chat system, but the program needs to know what ports aren't being refused access to incoming connections by a user's firewall, is there a way to check for this in your code? A program may not fail to bind a socket to a port even if the firewall is blocking that same port from incoming connections. Is there a way to check for open firewall ports?
Sidenote: This is purely for educational purposes and free of bad intentions, to be clear I am writing a chat system, and during testing, I was unable to connect desktop->laptop until I manually opened a port via allowing it through my firewall. This seemed a bit off to me, and unlike something that a programmer's code should require a user to do. Not to mention I don't want to leave the few people using this code at risk (if leaving a port permanently open does so). So It seems like I would be better suited finding a way to utilize ports that are already open to incoming TCP connections.
sidesidenote: all clients are running fedora
You have stumbled onto the second biggest issue governing the creation of new Internet applications nowadays. The first biggest of course is NAT, which is a strongly related issue (and hopefully going away eventually because of IPv6).
And there is no easy answer. One good answer is UPnP, but that's not an easy answer, and by no means universal. My network doesn't run it.
Another answer is to somehow tunnel everything you do over https (or http if you must). But that's a huge pain for something like a chat application.
I've been reading around on the www but just can't get the most important basics of P2P.
The diagram is like this:
[peer1]<-->[dsl-router1]<-->[central server]<-->[dsl-router2]<-->[peer2]
I'm developing a chat software on the central server. Chat messages being transfered thru' the central server well by now, however, I need to make the p2p file sharing feature because the bandwidth (the cable bandwith, not the transfer limit) of the server supposed for transfering chat messages only.
The problem is that, my software on central server knows the IPs and ports of router1 and router2, but not the peer1 and peer2 as these peers are behind the routers and don't have IP addresses.
How to actually transfer some data from peer1 to peer2 and vice versa without having this data passing thru' central server?
(and the worst case is that there is a wireless router between peer and dsl-router)
There are two basic ways of doing this. The new way is to use IGDP (opening a port via uPnP). This is described quite well here:
http://www.codeproject.com/Articles/13285/Using-UPnP-for-Programmatic-Port-Forwardings-and-N
If neither of the two nodes have a router supporting uPnP then another alternative is TCP hole punching, which is not perfect but works quite well in practice. This is described here:
http://www.brynosaurus.com/pub/net/p2pnat/
During some situations, "routers" supplied by the ISP may run on bridge mode, which directly exposes the peer computer on the internet (the computer gets a public internet address). If at least one side has this configuration (or in a similar situation that the peer client is not behind another device), then things should be rather straight forward: simply assign the central server's job to whoever that have this privilege.
In the other case where both peers only have a local address (e.g. 192.168.0.2) assigned to their computers, it would then be rather difficult to get through the routers; clients behind routers are for the most part unreachable from the outside unless they originated the request. Then, one solution to the problem is port forwarding. By doing port forwarding, either through explicitly written rules or UPnP, some ports on the peer computer is exposed to the public internet, as in the first situation where instead of only some ports the entire computer is exposed.
If you are without either of these, then there is no simple way to avoid sending through the central server. Though you could, potentially, find other peers who have the capability to transfer for others.
Windows knows when you have removed the network cable from your NIC. Is there a programmatic way to determine this via API in C++?
Note: I am not using .NET and this is for a closed LAN (not connected to Internet ever)
Raymond Chen blogged about something similar recently. Here is the relevant documentation. I think the MIB_IPADDR_DISCONNECTED flag is what you are looking for.
Use the Network List Manager api with the INetwork api.
You can register your app to receive callbacks when networks become connected/not connected.
Or you can get the list of networks and then check each of them to see if the machine is network connected or not
Remember that a windows machine will often have multiple networks set up (Ethernet, wifi, etc)
Remember that just because a network is connected, you may not have access to the internet. Eg you could have DNS or routing problems. Or you could be on a working network that is not connected to the internet.
Due to the above, many diagnostic tools also connect to a "known-good" internet server if they want to really know if they're connected or not. Something like google.com -- they spend a lot of money to make sure that their site is up all the time.
Finally, you can also have a semi-connected situation where packets are getting through but not enough to really enable communications to flow. To test this, don't just ping an internet site since that'd only be a pair of packets. Instead, open a TCP connection or something more than a ping.
Is there an existing Linux/POSIX C/C++ library or example code for how to rebind a socket from one physical interface to another?
For example, I have ping transmitting on a socket that is associated with a physical connection A and I want to rebind that socket to physical connection B and have the ping packets continue being sent and received on connection B (after a short delay during switch-over).
I only need this for session-less protocols.
Thank you
Update:
I am trying to provide failover solution for use with PPP and Ethernet devices.
I have a basic script which can accomplish 90% of the functionality through use of iptables, NAT and routing table.
The problem is when the failover occurs, the pings continue being sent on the secondary connection, however, their source IP is from the old connection.
I've spoken with a couple of people who work on commercial routers and their suggestion is to rebind the socket to the secondary interface.
Update 2:
I apologise for not specifying this earlier. This solution will run on a router. I cannot change the ping program because it will run on the clients computer. I used ping as just an example, any connection that is not session-based should be capable of being switched over. I tested this feature on several commercial routers and it does work. Unfortunately, their software is proprietary, however, from various conversations and testing, I found that they are re-binding the sockets on failover.
As of your updated post, the problem is that changing the routing info is not going to change the source address of your ping, it will just force it out the second interface. This answer contains some relevant info.
You'll need to change the ping program. You can use a socket-per-interface approach and somehow inform the program when to fail over. Or you will have to close the socket and then bind to the second interface.
You can get the interface info required a couple of ways including calling ioctl() with the SIOCGIFCONF option and looping through the returned structures to get the interface address info.
I do't think that's quite a well-defined operation. the physical interfaces have different MAC addresses, so unless you have a routing layer mapping them (NAT or the like) then they're going to have different IP addresses.
Ports are identified by a triple of <IP addr, Port number, protocol> so if your IP address changes the port is going to change.
What are you really trying to do here?
I'm not at all sure what you're trying to accomplish, but I have a guess... Are you trying to do some kind of failover? If so, then there are indeed ways to accomplish that, but why not do it in the OS instead of the application?
On one end you can use CARP, and on the other you can use interface trunking/bonding (terminology varies) in failover mode.