views:

341

answers:

2

I'm developing a home security application. One thing I'd like to do is automatically turn it off and on based on whether or not I'm at home. I have a phone with Wifi that automatically connects to my network when I'm home.

The phone connects and gets its address via DHCP. While I could configure it to use a static IP, I'd rather not. Is there any kind of 'Ping' or equivalent in C# / .Net that can take the MAC address of a device and tell me whether or not it's currently active on the network?

Edit: To clarify, I'm running software on a PC that I'd like to have be able to detect the phone on the same LAN.

Edit: Here is the code that I came up with, thanks to spoulson's help. It reliably detects whether or not any of the phones I'm interested in are in the house.

private bool PhonesInHouse()
{

    Ping p = new Ping();
    // My home network is 10.0.23.x, and the DHCP 
    // pool runs from 10.0.23.2 through 10.0.23.127.

    int baseaddr = 10;
    baseaddr <<= 8;
    baseaddr += 0;
    baseaddr <<= 8;
    baseaddr += 23;
    baseaddr <<= 8;

    // baseaddr is now the equivalent of 10.0.23.0 as an int.

    for(int i = 2; i<128; i++) {
        // ping every address in the DHCP pool, in a separate thread so 
        // that we can do them all at once
        IPAddress ip = new IPAddress(IPAddress.HostToNetworkOrder(baseaddr + i));
        Thread t = new Thread(() => 
             { try { Ping p = new Ping(); p.Send(ip, 1000); } catch { } });
        t.Start();
    }

    // Give all of the ping threads time to exit

    Thread.Sleep(1000);

    // We're going to parse the output of arp.exe to find out 
    // if any of the MACs we're interested in are online

    ProcessStartInfo psi = new ProcessStartInfo();
    psi.Arguments = "-a";
    psi.FileName = "arp.exe";
    psi.RedirectStandardOutput = true;
    psi.UseShellExecute = false;
    psi.CreateNoWindow = true;

    bool foundone = false;
    using (Process pro = Process.Start(psi))
    {
        using (StreamReader sr = pro.StandardOutput)
        {
            string s = sr.ReadLine();

            while (s != null)
            {
                if (s.Contains("Interface") || 
                    s.Trim() == "" || 
                    s.Contains("Address"))
                {
                    s = sr.ReadLine();
                    continue;
                }
                string[] parts = s.Split(new char[] { ' ' }, 
                    StringSplitOptions.RemoveEmptyEntries);

                // config.Phones is an array of strings, each with a MAC 
                // address in it.
                // It's up to you to format them in the same format as 
                // arp.exe
                foreach (string mac in config.Phones)
                {
                    if (mac.ToLower().Trim() == parts[1].Trim().ToLower())
                    {
                        try
                        {
                            Ping ping = new Ping();
                            PingReply pingrep = ping.Send(parts[0].Trim());
                            if (pingrep.Status == IPStatus.Success)
                            {
                                foundone = true;
                            }
                        }
                        catch { }
                        break;
                    }
                }
                s = sr.ReadLine();
            }
        }
    }

    return foundone;
}
A: 

You could use the RARP protocol to broadcast a request of who owns that MAC address. The owner will respond with its IP address. I don't know of a RARP tool or library to recommend, so you may consider writing your own network layer to send/receive these packets.

spoulson
you will need raw sockets to do this - let us know when you have done it cos we would like to see
pm100
+1  A: 

A different approach is to use ping and arp tools. Since ARP packets can only stay in the same broadcast domain, you could ping your network's broadcast address and every client will reply with an ARP response. Each of those responses are cached in your ARP table, which you can view with the command arp -a. So the rundown:

rem Clear ARP cache
netsh interface ip delete arpcache

rem Ping broadcast addr for network 192.168.1.0
ping -n 1 192.168.1.255

rem View ARP cache to see if the MAC addr is listed
arp -a

Some of these can be done in managed code, such as in the System.Net.NetworkInformation namespace.

Note: Clearing the ARP cache may have a marginal affect on network performance by clearing cached entries of other local servers. However, the cache is usually cleared every 20 minutes or less anyway.

spoulson
OK, now that I'm at home and have time to play with this, I just tried it, and the only devices it picks up are my desktop PC and my file server. It misses most of the other devices on the network (wireless adapter, phone, printer, other laptop computer, a couple of virtual machines...) The one device it does pick up is two switches away.
Aric TenEyck
To test, try pinging one of those missed devices by IP, then check `arp -a`. If that works, then perhaps the device doesn't respond to broadcast pings. :/ Maybe this isn't the best approach after all.
spoulson