12

I've been crawling in the web for about 5 hours now and couldn't find a solution for my problem:

My company is developing an educational game and I'm writing an autoupdater for it using Monotorrent. The game will be used in schools, but because most schools only have very weak internet connections there should only be one computer in the network that downloads from a httpseeder, and the others should leech from the one computer that is downloading from the httpseed.

So I get loads of IP-addresses from the tracker and need to filter out only the ones that are in the LAN.

Of course schools are sometimes quite strict with firewalls and there will be loads of routers and switches between some computers in a school.

I've already tried most solutions, things like

 NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces();

    foreach (NetworkInterface iface in interfaces)
    {
        IPInterfaceProperties properties = iface.GetIPProperties();

        foreach (UnicastIPAddressInformation address in properties.UnicastAddresses)
        {
            Console.WriteLine(
                "{0} (Mask: {1})",
                address.Address,
                address.IPv4Mask
                );
        }
    }

Or similar techniques only deliver the information of the router/switch/whatever.

So in a nutshell, what I want to do is check if a given IP is accessible via LAN.

I'd really appreciate any help because this feature is the last one remaining :)

Squirrel
  • 137
  • 1
  • 7
  • do all computers containing the game connect to your internet server ? – Yahia Aug 29 '11 at 15:35
  • 2
    There is a limited amount of IP-addresses that are allowed for internal use, the private sub nets. Wouldn't that be enough identification? It is very rare to use public IP-addresses and then firewall them, because you don't want to waste IPv4 addresses. IPv6 is a whole different matter. – jishi Aug 29 '11 at 15:37
  • @jishi you are assuming that networks at schools are set up according to recommendations. Although the private ranges are recommended, there is nothing stopping you from using public ones. – Jonathan Dickinson Aug 29 '11 at 16:10
  • @ Yahia all connect to the same tracker yes, but only one of them connects to the html-seeder, so that all others download from that computer (that way I save bandwith because the game is only downloaded by one computer and shared across the lan) – Squirrel Aug 30 '11 at 07:37
  • @Jonathan Dickinson Well, if they have used public IPs and for NAT then they probably have bigger issues than a few clients that generate a little more bandwidth... – jishi Aug 30 '11 at 10:12
  • @jishi definitely, but your application should still try its best to behave predictably. – Jonathan Dickinson Aug 30 '11 at 10:39
  • @Jonathan Dickinson It is of course nice if an app can take misconfigurations in consideration, but I wouldn't call it a necessity. However, there are other viable and more robust solutions, I just wanted to give a simple solution if it can be prone to failure. – jishi Aug 30 '11 at 11:20
  • @jishi - of course that would work in the 99% percentile and is really simple (just check if the first byte is 10 or 192). – Jonathan Dickinson Aug 30 '11 at 11:56
  • well for now in the office it works perfectly, unfortunately I guess I'll only be able to test it earliest at weekend, but I'll post my results then immediately, thanks again all of you (especially jonathan dickinson) – Squirrel Aug 30 '11 at 13:40

3 Answers3

19

You could take advantage of TTL. With a TTL of 1 the packet won't be able to make it to the internet:

private static bool IsLanIP(IPAddress address)
{
    var ping = new Ping();
    var rep = ping.Send(address, 100, new byte[] { 1 }, new PingOptions()
    {
        DontFragment = true,
        Ttl = 1
    });
    return rep.Status != IPStatus.TtlExpired && rep.Status != IPStatus.TimedOut && rep.Status != IPStatus.TimeExceeded;
}

However, remember that it is called an IPv4 mask for a reason - you can use it as one (so here is your algorithmic solution):

private static bool IsLanIP(IPAddress address)
{
    var interfaces = NetworkInterface.GetAllNetworkInterfaces();
    foreach (var iface in interfaces)
    {
        var properties = iface.GetIPProperties();
        foreach (var ifAddr in properties.UnicastAddresses)
        {
            if (ifAddr.IPv4Mask != null && 
                ifAddr.Address.AddressFamily == AddressFamily.InterNetwork &&
                CheckMask(ifAddr.Address, ifAddr.IPv4Mask, address))
                return true;
        }
    }
    return false;
}

private static bool CheckMask(IPAddress address, IPAddress mask, IPAddress target)
{
    if (mask == null)
        return false;

    var ba = address.GetAddressBytes();
    var bm = mask.GetAddressBytes();
    var bb = target.GetAddressBytes();

    if (ba.Length != bm.Length || bm.Length != bb.Length)
        return false;

    for (var i = 0; i < ba.Length; i++)
    {
        int m = bm[i];

        int a = ba[i] & m;
        int b = bb[i] & m;

        if (a != b)
            return false;
    }

    return true;
}
Jonathan Dickinson
  • 9,050
  • 1
  • 37
  • 60
  • the second solution seems to work thanks alot, though I'm not sure about the TTL-Solution, correct me if I'm wrong (I'm really not sure) but istn't the ttl also decremented when passing by a local switch or router? Because if so, it wouldn't get behind the local switches? – Squirrel Aug 30 '11 at 07:30
  • @Squirrel as far as I know it only gets decremented when passing a router (not a switch or hub); and a LAN should only have a single router. However, the mask solution is the least likely to give false results. – Jonathan Dickinson Aug 30 '11 at 07:49
  • 1
    Just checking if the IP is in the same "LAN" doesn't really tell if you are on a LAN or if you just happen to have an ISP that serves you IP-adresses. You could be part of a /24 or even a /22 net with a public IP, then you are "not" on a LAN, just the same ISP. – jishi Aug 30 '11 at 11:22
  • @jishi your router will have the IP from your ISP; and I am not sure if a gateway can be configured to 'passthrough' directly to the internet - even so your ISP/NS/Country wouldn't be able to allocate that IP range with the IANA anyway. So you can botch it from one end, but not the other. – Jonathan Dickinson Aug 30 '11 at 12:00
  • 2
    Checked it out in a school, the solution with the IPv4 Mask worked out just fine. thanks alot again – Squirrel Sep 05 '11 at 10:35
  • Can anyone offer a solution that would be valid if the client is using either ip4 or ip6? – Watson Aug 16 '12 at 17:26
  • @user190084 technically this should work with IPv6, but I haven't tested it. Are you getting any errors? Edit: At least if you remove workaround the IPv4-specific check. – Jonathan Dickinson Aug 17 '12 at 15:00
1

Typically any IPs like 10.x.x.x (Class A) or 192.x.x.x (Class C) can be safely assumed to be inside a private local area network. IP Classications

Arun
  • 2,493
  • 15
  • 12
1

One thing that you could possibly use is to try and communicate between clients using multicast. Most firewalls and routers would block multicast traffic (and ISPs most definitely), meaning that you wouldn't be able to join a multicast group if no other client is on the lan. A dumb switch would pass on the traffic, a layer 3-switch might block it, or could allow it depending on configuration. Either way, if the layer 3 switch block it, you are probably on different subnets altogether anyway so all other options would fail as well.

One technology that comes to mind is SSDP ( http://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol ) which would serve your purpose pretty good I believe. That way you don't really need to figure out if you are on a LAN or not, just search for another node that is actively downloading, if you can't find one, start downloading yourself.

Since SSDP is a standard used in uPnP you would probably be able to find decent implementations you could work with.

jishi
  • 24,126
  • 6
  • 49
  • 75